Line data Source code
1 : /*
2 : * Copyright (c) 2024 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #include <app/data-model-provider/ActionReturnStatus.h>
18 : #include <lib/core/CHIPConfig.h>
19 : #include <lib/core/CHIPError.h>
20 : #include <lib/support/CodeUtils.h>
21 : #include <protocols/interaction_model/StatusCode.h>
22 :
23 : #include <lib/support/StringBuilder.h>
24 :
25 : namespace chip {
26 : namespace app {
27 : namespace DataModel {
28 :
29 : using Protocols::InteractionModel::ClusterStatusCode;
30 : using Protocols::InteractionModel::Status;
31 :
32 : namespace {
33 :
34 19 : bool StatusIsTheSameAsError(const ClusterStatusCode & status, const CHIP_ERROR & err)
35 : {
36 19 : auto cluster_code = status.GetClusterSpecificCode();
37 19 : if (!cluster_code.has_value())
38 : {
39 : // there exist Status::Success, however that may not be encoded
40 : // as a CHIP_ERROR_IM_GLOBAL_STATUS_VALUE as it is just as well a CHIP_NO_ERROR.
41 : // handle that separately
42 14 : if ((status.GetStatus() == Status::Success) && (err == CHIP_NO_ERROR))
43 : {
44 2 : return true;
45 : }
46 :
47 12 : return err == CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status.GetStatus());
48 : }
49 :
50 5 : if (status.GetStatus() != Status::Failure)
51 : {
52 3 : return false;
53 : }
54 :
55 2 : return err == CHIP_ERROR_IM_CLUSTER_STATUS_VALUE(*cluster_code);
56 : }
57 :
58 : } // namespace
59 :
60 196 : bool ActionReturnStatus::operator==(const ActionReturnStatus & other) const
61 : {
62 196 : if (mReturnStatus == other.mReturnStatus)
63 : {
64 162 : return true;
65 : }
66 :
67 34 : const ClusterStatusCode * thisStatus = std::get_if<ClusterStatusCode>(&mReturnStatus);
68 34 : const ClusterStatusCode * otherStatus = std::get_if<ClusterStatusCode>(&other.mReturnStatus);
69 :
70 34 : const CHIP_ERROR * thisErr = std::get_if<CHIP_ERROR>(&mReturnStatus);
71 34 : const CHIP_ERROR * otherErr = std::get_if<CHIP_ERROR>(&other.mReturnStatus);
72 :
73 34 : if (thisStatus && otherErr)
74 : {
75 9 : return StatusIsTheSameAsError(*thisStatus, *otherErr);
76 : }
77 :
78 25 : if (otherStatus && thisErr)
79 : {
80 10 : return StatusIsTheSameAsError(*otherStatus, *thisErr);
81 : }
82 :
83 15 : return false;
84 : }
85 :
86 420 : CHIP_ERROR ActionReturnStatus::GetUnderlyingError() const
87 : {
88 :
89 420 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
90 : {
91 415 : return *err;
92 : }
93 :
94 5 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
95 : {
96 5 : if (status->IsSuccess())
97 : {
98 2 : return CHIP_NO_ERROR;
99 : }
100 :
101 3 : std::optional<ClusterStatus> code = status->GetClusterSpecificCode();
102 :
103 4 : return code.has_value() ? CHIP_ERROR_IM_CLUSTER_STATUS_VALUE(*code)
104 4 : : CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status->GetStatus());
105 : }
106 :
107 0 : if (const ActionReturnStatus::FixedStatus * status = std::get_if<ActionReturnStatus::FixedStatus>(&mReturnStatus))
108 : {
109 0 : if (*status == ActionReturnStatus::FixedStatus::kWriteSuccessNoOp)
110 : {
111 0 : return CHIP_NO_ERROR;
112 : }
113 : }
114 :
115 0 : chipDie();
116 : }
117 :
118 5215 : ClusterStatusCode ActionReturnStatus::GetStatusCode() const
119 : {
120 5215 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
121 : {
122 20 : return *status;
123 : }
124 :
125 5195 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
126 : {
127 5195 : return ClusterStatusCode(*err);
128 : }
129 :
130 0 : if (const ActionReturnStatus::FixedStatus * status = std::get_if<ActionReturnStatus::FixedStatus>(&mReturnStatus))
131 : {
132 0 : if (*status == ActionReturnStatus::FixedStatus::kWriteSuccessNoOp)
133 : {
134 0 : return ClusterStatusCode(CHIP_NO_ERROR);
135 : }
136 : }
137 :
138 : // all std::variant cases exhausted
139 0 : chipDie();
140 : }
141 :
142 20353 : bool ActionReturnStatus::IsSuccess() const
143 : {
144 20353 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
145 : {
146 15116 : return (*err == CHIP_NO_ERROR);
147 : }
148 :
149 5237 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
150 : {
151 5237 : return status->IsSuccess();
152 : }
153 :
154 0 : if (const ActionReturnStatus::FixedStatus * status = std::get_if<ActionReturnStatus::FixedStatus>(&mReturnStatus))
155 : {
156 0 : return (*status == ActionReturnStatus::FixedStatus::kWriteSuccessNoOp);
157 : }
158 :
159 : // all std::variant cases exhausted
160 0 : chipDie();
161 : }
162 :
163 3 : bool ActionReturnStatus::IsNoOpSuccess() const
164 : {
165 3 : if (const ActionReturnStatus::FixedStatus * status = std::get_if<ActionReturnStatus::FixedStatus>(&mReturnStatus))
166 : {
167 0 : return (*status == ActionReturnStatus::FixedStatus::kWriteSuccessNoOp);
168 : }
169 :
170 : // NoOp Success only works with FixedStatus, any other type should return false since it is not
171 : // supported specifically by the type.
172 3 : return false;
173 : }
174 :
175 796 : bool ActionReturnStatus::IsOutOfSpaceEncodingResponse() const
176 : {
177 796 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
178 : {
179 794 : return (*err == CHIP_ERROR_NO_MEMORY) || (*err == CHIP_ERROR_BUFFER_TOO_SMALL);
180 : }
181 :
182 2 : return false;
183 : }
184 :
185 8 : const char * ActionReturnStatus::c_str(ActionReturnStatus::StringStorage & storage) const
186 : {
187 8 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
188 : {
189 : #if CHIP_CONFIG_ERROR_FORMAT_AS_STRING
190 3 : return err->Format(); // any length
191 : #else
192 : storage.formatBuffer.Reset().AddFormat("%" CHIP_ERROR_FORMAT, err->Format());
193 : return storage.formatBuffer.c_str();
194 : #endif
195 : }
196 :
197 5 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
198 : {
199 5 : storage.formatBuffer.Reset();
200 :
201 : #if CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
202 5 : storage.formatBuffer.AddFormat("%s(%d)", Protocols::InteractionModel::StatusName(status->GetStatus()),
203 5 : static_cast<int>(status->GetStatus()));
204 : #else
205 : if (status->IsSuccess())
206 : {
207 : storage.formatBuffer.Add("Success");
208 : }
209 : else
210 : {
211 : storage.formatBuffer.AddFormat("Status<%d>", static_cast<int>(status->GetStatus()));
212 : }
213 : #endif
214 :
215 5 : std::optional<ClusterStatus> clusterCode = status->GetClusterSpecificCode();
216 5 : if (clusterCode.has_value())
217 : {
218 2 : storage.formatBuffer.AddFormat(", Code %d", static_cast<int>(*clusterCode));
219 : }
220 5 : return storage.formatBuffer.c_str();
221 : }
222 :
223 : // all std::variant cases exhausted
224 0 : chipDie();
225 : }
226 :
227 : } // namespace DataModel
228 : } // namespace app
229 : } // namespace chip
|