1
+ /* *****************************************************************************
2
+ * # License
3
+ * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
4
+ ******************************************************************************
5
+ * The licensor of this software is Silicon Laboratories Inc. Your use of this
6
+ * software is governed by the terms of Silicon Labs Master Software License
7
+ * Agreement (MSLA) available at
8
+ * www.silabs.com/about-us/legal/master-software-license-agreement. This
9
+ * software is distributed to you in Source Code format and is governed by the
10
+ * sections of the MSLA applicable to Source Code.
11
+ *
12
+ *****************************************************************************/
13
+
14
+ /* *
15
+ * @defgroup zwave_frame_parser C++ Z-Wave Frame Handler Helper
16
+ * @brief C++ definitions for handling Z-Wave Frames
17
+ *
18
+ * This group is used to handle Z-Wave frame and link their contents with the attribute store.
19
+ *
20
+ * @{
21
+ */
22
+
23
+ #ifndef ZWAVE_FRAME_GENERATOR_HPP
24
+ #define ZWAVE_FRAME_GENERATOR_HPP
25
+
26
+ #ifdef __cplusplus
27
+
28
+ // Unify includes
29
+ #include " attribute_store.h"
30
+ #include " sl_status.h"
31
+
32
+ // Cpp includes
33
+ #include < vector>
34
+
35
+ /* *
36
+ * @class zwave_frame_generator
37
+ * @brief Generate frames for Z-Wave commands based on attribute store values
38
+ *
39
+ * Mainly used to generate Set or Get frame to send to Z-Wave devices
40
+ *
41
+ * You can either set raw bytes, or let the function get the value from the attribute store for
42
+ * you. You are able to specify if you want a Desired or Reported value.
43
+ *
44
+ * @code{.cpp}
45
+ * // Only needed to be instantiated once
46
+ * static zwave_frame_generator frame_generator(COMMAND_CLASS_SWITCH_BINARY);
47
+ *
48
+ * // On a frame callback :
49
+ * static sl_status_t zwave_command_class_set(
50
+ * attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length) {
51
+ *
52
+ * // We don't use frame_length here since we need to set it manually
53
+ * constexpr uint8_t expected_frame_size = 3;
54
+ * try {
55
+ * frame_generator.initialize_frame(SWITCH_BINARY_SET, frame, expected_frame_size);
56
+ * frame_generator.add_raw_byte(0x01);
57
+ * frame_generator.add_value(my_binary_node, REPORTED_ATTRIBUTE);
58
+ *
59
+ * // Will take the DESIRED_ATTRIBUTE value from my_node and shift it 2 bits to the left,
60
+ * // then add 0b1 shifted 7 bits to the left.
61
+ * // Result value (if desired value is 0b11) : 0b10001100
62
+ * std::vector<zwave_frame_generator::shifted_value> values_mix = {
63
+ * {.left_shift = 2,
64
+ * .node = my_node,
65
+ * .node_value_state = DESIRED_ATTRIBUTE},
66
+ * {.left_shift = 7, .raw_value = 0b1},
67
+ * };
68
+ * frame_generator.add_shifted_values(values_mix);
69
+ *
70
+ * frame_generator.validate_frame(frame_length);
71
+ *
72
+ * } catch (const std::exception &e) {
73
+ * sl_log_error(LOG_TAG, "Error while generating frame : %s", e.what());
74
+ * return SL_STATUS_FAIL;
75
+ * }
76
+ *
77
+ * return SL_STATUS_OK;
78
+ * }
79
+ *
80
+ * @endcode
81
+ */
82
+ class zwave_frame_generator
83
+ {
84
+ public:
85
+ /* *
86
+ * @brief Represent a value that needs to be shifted before being added to the frame.
87
+ *
88
+ * You can either specify the node and value state to get the value from the attribute store
89
+ * or provide a raw value to be shifted.
90
+ *
91
+ * @note If you provide a node, it will read a uint8_t value from it.
92
+ */
93
+ struct shifted_value {
94
+ /* *
95
+ * @brief The number of bits to shift the value (left)
96
+ */
97
+ uint8_t left_shift = 0 ;
98
+ /* *
99
+ * @brief Node to get the value from (uint8_t). If ATTRIBUTE_STORE_INVALID_NODE, use raw_value
100
+ */
101
+ attribute_store_node_t node = ATTRIBUTE_STORE_INVALID_NODE;
102
+ /* *
103
+ * @brief State of the value to get from the node. Only used if node is not ATTRIBUTE_STORE_INVALID_NODE
104
+ */
105
+ attribute_store_node_value_state_t node_value_state = REPORTED_ATTRIBUTE;
106
+ /* *
107
+ * @brief Raw value to shift. Only used if node is ATTRIBUTE_STORE_INVALID_NODE
108
+ */
109
+ uint8_t raw_value = 0 ;
110
+ };
111
+
112
+ /* *
113
+ * @brief Constructor
114
+ *
115
+ * @param zwave_command_class The Z-Wave command class to use in the header of all generated commands
116
+ */
117
+ explicit zwave_frame_generator (uint8_t zwave_command_class);
118
+ ~zwave_frame_generator () = default ;
119
+
120
+ /* *
121
+ * @brief Initialize a new Z-Wave frame on the given data section.
122
+ *
123
+ * @note This will reset the internal counter to 0 and update the data section provided with other functions.
124
+ *
125
+ * After calling this function your frame will look like :
126
+ * 0: zwave_command_class (from constructor)
127
+ * 1: zwave_command_id (from this function)
128
+ *
129
+ * @param zwave_command_id The Z-Wave command ID to use in the header of the frame
130
+ * @param raw_data The data section of the frame (must be allowed an valid from this address to data_size bytes after)
131
+ * @param data_size The size of the data section (we use uint16_t to match Unify API)
132
+ */
133
+ void initialize_frame (uint8_t zwave_command_id,
134
+ uint8_t *raw_data,
135
+ uint16_t data_size);
136
+
137
+ /* *
138
+ * @brief Add a raw byte to the Z-Wave frame
139
+ *
140
+ * @param byte The byte to add to the frame
141
+ */
142
+ void add_raw_byte (uint8_t byte);
143
+
144
+ /* *
145
+ * @brief Add the value contained in the given node to the Z-Wave frame
146
+ *
147
+ * @throws std::runtime_error if the node is invalid or if the value can't be read
148
+ *
149
+ * @note The size of the value is automatically determined by the attribute store.
150
+ * Numerical values will be stored in big-endian (MSB first LSB last).
151
+ * Other formats will keep their original order.
152
+ *
153
+ * @param node The node to get the value from
154
+ * @param node_value_state The state of the value to get from the node
155
+ *
156
+ */
157
+ void add_value (attribute_store_node_t node,
158
+ attribute_store_node_value_state_t node_value_state
159
+ = REPORTED_ATTRIBUTE);
160
+ /* *
161
+ * @brief Add a shifted value to the Z-Wave frame
162
+ *
163
+ * You can either specify a raw value to be shifted, or directly pass the attribute
164
+ * store node.
165
+ *
166
+ * @see shifted_value
167
+ *
168
+ * @param shifted_values The shifted value to add to the frame
169
+ */
170
+ void add_shifted_values (const std::vector<shifted_value> &shifted_values);
171
+ /* *
172
+ * @brief Add a shifted value to the Z-Wave frame (single value version)
173
+ *
174
+ * Convenience function to add a single shifted value to the frame.
175
+ *
176
+ * @see shifted_value
177
+ *
178
+ * @param shifted_values The shifted value to add to the frame
179
+ */
180
+ void add_shifted_values (const shifted_value &shifted_values);
181
+
182
+ /* *
183
+ * @brief Validate the frame length and throw an error if it is not the expected length
184
+ *
185
+ * @note We don't use bool here since the all the function throw an error if anything goes wrong
186
+ *
187
+ * @param frame_length Will set the frame length if current frame length is equal to expected length
188
+ */
189
+ void validate_frame (uint16_t *frame_length) const ;
190
+
191
+ /* *
192
+ * @brief Generate a Z-Wave frame with no arguments
193
+ *
194
+ * This function is used to generate a Z-Wave frame with no arguments like a simple Get command.
195
+ * Since it is used for convenience, this method doesn't throw an exception and return a status instead.
196
+ *
197
+ * @param zwave_command_id The Z-Wave command ID to use in the header of the frame
198
+ * @param raw_data The data section of the frame (must be able to write 2 byte to this address)
199
+ * @param frame_length Frame length pointer (set to 2)
200
+ *
201
+ * @return SL_STATUS_OK if the frame was generated successfully, SL_STATUS_FAIL otherwise
202
+ */
203
+ sl_status_t generate_no_args_frame (uint8_t zwave_command_id,
204
+ uint8_t *raw_data,
205
+ uint16_t *frame_length);
206
+
207
+ private:
208
+ /* *
209
+ * @brief Helper function to get the raw data from the attribute store
210
+ *
211
+ * @note Number will be returned in little-endian (LSB first MSB last)
212
+ *
213
+ * @param node The node to get the value from
214
+ * @param node_value_state The state of the value to get from the node
215
+ *
216
+ * @return The raw data from the attribute store
217
+ */
218
+ std::vector<uint8_t > helper_get_raw_data (
219
+ attribute_store_node_t node,
220
+ attribute_store_node_value_state_t node_value_state) const ;
221
+
222
+ // Current Z-Wave command class used in the header of all generated commands
223
+ const uint8_t current_command_class;
224
+ // Vector wrapper around raw frame data. See initialize_frame()
225
+ uint8_t *current_zwave_frame;
226
+ // Current Z-Wave frame size
227
+ uint16_t current_zwave_frame_size = 0 ;
228
+ // Current Z-Wave frame index (we use uint16_t to match Unify API)
229
+ uint16_t current_zwave_frame_index = 0 ;
230
+ };
231
+
232
+ #endif // __cplusplus
233
+ #endif // ZWAVE_FRAME_GENERATOR_HPP
0 commit comments