Skip to content

Commit cf9a4fc

Browse files
committed
SiliconLabsGH-43: New Command Class C++ API
Forwarded: SiliconLabs#43 Bug-SiliconLabs: UIC-3222 Bug-Github: SiliconLabs#43
1 parent 37cc33b commit cf9a4fc

32 files changed

+3495
-64
lines changed

applications/zpc/components/zpc_attribute_store/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ add_library(
66
src/zpc_attribute_store_register_default_attribute_type_data.cpp
77
src/zpc_attribute_store_type_registration.cpp
88
src/zwave_association_toolbox.cpp
9-
src/zwave_utils.c)
9+
src/zwave_utils.c
10+
src/zwave_frame_parser.cpp
11+
src/zwave_frame_generator.cpp
12+
)
1013

1114
target_include_directories(
1215
zpc_attribute_store
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
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

Comments
 (0)