Skip to content

Commit 95c59dc

Browse files
silabs-borislrzr
authored andcommitted
uic: zpc: Pull request #2808: UIC-3309: Create ZPC C++ helper & update existings
Merge in UIC/uic from blabbe/feat/UIC-3309-zpc-create-helpers to develop (cherry picked from commit b0fbd5c8d9335aa47266f8ff8ca31560d92b5159) Last-Update: 2025-01-30 Forwarded: SiliconLabsSoftware#11 Signed-off-by: Philippe Coval <philippe.coval@silabs.com>
1 parent 622f892 commit 95c59dc

39 files changed

+4965
-1346
lines changed

.vscode/zpc.code-snippets

+343-25
Large diffs are not rendered by default.

applications/zpc/components/zpc_attribute_store/CMakeLists.txt

+4-1
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

applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h

+36
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,42 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BASIC_DURATION,
186186
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BASIC_PROBE_STATUS,
187187
((COMMAND_CLASS_BASIC << 8) | 0x04))
188188

189+
///////////////////////////////////
190+
// Battery Command Class
191+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_VERSION,
192+
ZWAVE_CC_VERSION_ATTRIBUTE(COMMAND_CLASS_BATTERY))
193+
// Battery report
194+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_BATTERY_LEVEL,
195+
((COMMAND_CLASS_BATTERY << 8) | 0x02))
196+
// V2+
197+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_REPLACE_RECHARGE,
198+
((COMMAND_CLASS_BATTERY << 8) | 0x03))
199+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_CHARGING_STATUS,
200+
((COMMAND_CLASS_BATTERY << 8) | 0x04))
201+
// This ID are shifted since we are ensuring compatibility with the legacy implementation
202+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_RECHARGEABLE,
203+
((COMMAND_CLASS_BATTERY << 8) | 0x09))
204+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_BACKUP_BATTERY,
205+
((COMMAND_CLASS_BATTERY << 8) | 0x0A))
206+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_OVERHEATING,
207+
((COMMAND_CLASS_BATTERY << 8) | 0x0B))
208+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_LOW_FLUID,
209+
((COMMAND_CLASS_BATTERY << 8) | 0x0C))
210+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_DISCONNECTED,
211+
((COMMAND_CLASS_BATTERY << 8) | 0x0D))
212+
// V3+
213+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_LOW_TEMPERATURE,
214+
((COMMAND_CLASS_BATTERY << 8) | 0x0E))
215+
// Battery health V2+
216+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_MAXIMUM_CAPACITY,
217+
((COMMAND_CLASS_BATTERY << 8) | 0x05))
218+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_SCALE,
219+
((COMMAND_CLASS_BATTERY << 8) | 0x06))
220+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_PRECISION,
221+
((COMMAND_CLASS_BATTERY << 8) | 0x07))
222+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_BATTERY_HEALTH_BATTERY_TEMPERATURE,
223+
((COMMAND_CLASS_BATTERY << 8) | 0x08))
224+
189225
//Door Lock Command Class
190226

191227
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_DOOR_LOCK_CAPABILITIES,
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)