@@ -83,6 +83,101 @@ std::set<user_credential_slot_message_callback_t>
8383 user_credential_slot_message_callback; // NOSONAR - false positive since it is warped in a namespace
8484} // namespace
8585
86+ /* *
87+ * @brief Keep track of the interview state
88+ *
89+ * User interview start with a get on User 0 to get the first user.
90+ * We keep this node to store all the credentials that are not assigned to a user.
91+ *
92+ * So we need to set its reported in the first User Report otherwise the first GET will
93+ * never be marked as resolved.
94+ *
95+ * We also need to keep track of the next user to interview, so we can first get all the
96+ * credential for the current user before moving to the next one.
97+ */
98+ namespace users_interview_state
99+ {
100+ // WARNING : Use functions instead of those variables
101+ // Next user ID to be interviewed
102+ user_credential_user_unique_id_t next_user_id = 0 ;
103+ // Special node for user 0
104+ // Used to resolve it in the report instead of in the get to prevent resolver issues
105+ attribute_store::attribute user_0_node = ATTRIBUTE_STORE_INVALID_NODE;
106+
107+ /* *
108+ * @brief Mark an node as the user 0 node
109+ *
110+ * @param node Node to mark as user 0
111+ */
112+ void set_user_0_node (attribute_store::attribute node)
113+ {
114+ sl_log_debug (LOG_TAG, " Starting interview for all users on the device." );
115+ user_0_node = node;
116+ }
117+
118+ /* *
119+ * @brief Resolve user 0 if needed
120+ */
121+ void resolve_user_0_node ()
122+ {
123+ if (user_0_node == ATTRIBUTE_STORE_INVALID_NODE) {
124+ return ;
125+ }
126+
127+ try {
128+ user_0_node.set_reported <user_credential_user_unique_id_t >(0 );
129+ user_0_node = ATTRIBUTE_STORE_INVALID_NODE;
130+ } catch (const std::exception &e) {
131+ sl_log_error (LOG_TAG, " Error while setting user 0 node : %s" , e.what ());
132+ }
133+ }
134+
135+ /* *
136+ * @brief Schedule the next user interview
137+ *
138+ * @param user_id User ID to interview next
139+ */
140+ void schedule_next_user_interview (user_credential_user_unique_id_t user_id)
141+ {
142+ sl_log_debug (LOG_TAG, " Schedule a get for next User ID :%d" , next_user_id);
143+ next_user_id = user_id;
144+ }
145+
146+ /* *
147+ * @brief Trigger a get for the next user
148+ *
149+ * If there is not next user, we will trigger the all users checksum get
150+ * (if supported)
151+ *
152+ * @param endpoint_node Current endpoint node
153+ */
154+ void trigger_get_for_next_user (attribute_store::attribute endpoint_node)
155+ {
156+ // If we get here it means that we have finished the interview for users and
157+ // their credentials
158+ if (next_user_id == 0 ) {
159+ sl_log_debug (LOG_TAG, " User interview finished" );
160+ // Check if we supports all users checksum to compute it
161+ user_credential::user_capabilities capabilities (endpoint_node);
162+ if (capabilities.is_all_users_checksum_supported ()) {
163+ // This will do nothing if the node already exists
164+ // Otherwise it will trigger all_users_checksum_get
165+ endpoint_node.emplace_node (ATTRIBUTE (ALL_USERS_CHECKSUM));
166+ }
167+ return ;
168+ }
169+
170+ sl_log_debug (LOG_TAG, " Trigger a get for next User ID :%d" , next_user_id);
171+
172+ endpoint_node.emplace_node (ATTRIBUTE (USER_UNIQUE_ID),
173+ next_user_id,
174+ DESIRED_ATTRIBUTE);
175+
176+ // Reset state
177+ next_user_id = 0 ;
178+ }
179+ } // namespace users_interview_state
180+
86181// ///////////////////////////////////////////////////////////////////////////
87182// Callbacks
88183// ///////////////////////////////////////////////////////////////////////////
@@ -1036,6 +1131,8 @@ sl_status_t zwave_command_class_user_credential_credential_handle_report(
10361131 next_credential_slot);
10371132 } else {
10381133 sl_log_debug (LOG_TAG, " No more credential to get." );
1134+ // Trigger the next user interview if any
1135+ users_interview_state::trigger_get_for_next_user (endpoint_node);
10391136 }
10401137
10411138 } catch (const std::exception &e) {
@@ -1523,9 +1620,7 @@ static sl_status_t zwave_command_class_user_credential_user_get(
15231620
15241621 // This special user ID will contains the unaffected credentials.
15251622 if (user_id == 0 ) {
1526- sl_log_debug (LOG_TAG, " Starting interview for all users on the device." );
1527- user_unique_id_node.clear_desired ();
1528- user_unique_id_node.set_reported (user_id);
1623+ users_interview_state::set_user_0_node (user_unique_id_node);
15291624 }
15301625
15311626 return SL_STATUS_OK;
@@ -1553,6 +1648,10 @@ sl_status_t zwave_command_class_user_credential_user_handle_report(
15531648 attribute_store::attribute endpoint_node (
15541649 zwave_command_class_get_endpoint_node (connection_info));
15551650
1651+ // Resolve user 0 node if needed
1652+ // We need to do that here so that the attribute store mark this node as resolved
1653+ users_interview_state::resolve_user_0_node ();
1654+
15561655 const uint8_t expected_min_size = 16 ;
15571656
15581657 try {
@@ -1699,23 +1798,16 @@ sl_status_t zwave_command_class_user_credential_user_handle_report(
16991798 if (next_user_id != 0
17001799 && user_report_type == user_report_type_t ::RESPONSE_TO_GET) {
17011800 if (!user_exists (endpoint_node, next_user_id)) {
1702- sl_log_debug (LOG_TAG, " Trigger a get for next user (%d)" , next_user_id);
1703- endpoint_node.add_node (ATTRIBUTE (USER_UNIQUE_ID))
1704- .set_desired (next_user_id);
1801+ users_interview_state::schedule_next_user_interview (next_user_id);
17051802 } else {
17061803 sl_log_error (LOG_TAG,
17071804 " User %d already exists. Not discovering more users." ,
17081805 next_user_id);
17091806 }
17101807 } else {
1711- sl_log_debug (LOG_TAG, " No more users to discover" );
1712- // Check if we supports all users checksum to compute it
1713- user_credential::user_capabilities capabilities (endpoint_node);
1714- if (capabilities.is_all_users_checksum_supported ()) {
1715- // This will do nothing if the node already exists
1716- // Otherwise it will trigger all_users_checksum_get
1717- endpoint_node.emplace_node (ATTRIBUTE (ALL_USERS_CHECKSUM));
1718- }
1808+ sl_log_debug (LOG_TAG,
1809+ " User %d is the last user to be discovered." ,
1810+ current_user_id);
17191811 }
17201812 } catch (const std::exception &e) {
17211813 sl_log_error (LOG_TAG,
0 commit comments