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 71 : bool StatusIsTheSameAsError(const ClusterStatusCode & status, const CHIP_ERROR & err)
35 : {
36 71 : auto cluster_code = status.GetClusterSpecificCode();
37 71 : 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 113 : if ((status.GetStatus() == Status::Success) && (err == CHIP_NO_ERROR))
43 : {
44 45 : return true;
45 : }
46 :
47 42 : 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 4 : return err == CHIP_ERROR_IM_CLUSTER_STATUS_VALUE(*cluster_code);
56 : }
57 :
58 : } // namespace
59 :
60 864 : bool ActionReturnStatus::operator==(const ActionReturnStatus & other) const
61 : {
62 864 : if (mReturnStatus == other.mReturnStatus)
63 : {
64 776 : return true;
65 : }
66 :
67 88 : const ClusterStatusCode * thisStatus = std::get_if<ClusterStatusCode>(&mReturnStatus);
68 88 : const ClusterStatusCode * otherStatus = std::get_if<ClusterStatusCode>(&other.mReturnStatus);
69 :
70 88 : const CHIP_ERROR * thisErr = std::get_if<CHIP_ERROR>(&mReturnStatus);
71 88 : const CHIP_ERROR * otherErr = std::get_if<CHIP_ERROR>(&other.mReturnStatus);
72 :
73 88 : if (thisStatus && otherErr)
74 : {
75 40 : return StatusIsTheSameAsError(*thisStatus, *otherErr);
76 : }
77 :
78 48 : if (otherStatus && thisErr)
79 : {
80 31 : return StatusIsTheSameAsError(*otherStatus, *thisErr);
81 : }
82 :
83 17 : return false;
84 : }
85 :
86 452 : CHIP_ERROR ActionReturnStatus::GetUnderlyingError() const
87 : {
88 :
89 452 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
90 : {
91 422 : return *err;
92 : }
93 :
94 30 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
95 : {
96 30 : if (status->IsSuccess())
97 : {
98 24 : return CHIP_NO_ERROR;
99 : }
100 :
101 6 : std::optional<ClusterStatus> code = status->GetClusterSpecificCode();
102 :
103 7 : return code.has_value() ? CHIP_ERROR_IM_CLUSTER_STATUS_VALUE(*code)
104 7 : : 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 5273 : ClusterStatusCode ActionReturnStatus::GetStatusCode() const
119 : {
120 5273 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
121 : {
122 77 : return *status;
123 : }
124 :
125 5196 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
126 : {
127 5196 : 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 21535 : bool ActionReturnStatus::IsSuccess() const
143 : {
144 21535 : if (const CHIP_ERROR * err = std::get_if<CHIP_ERROR>(&mReturnStatus))
145 : {
146 32132 : return (*err == CHIP_NO_ERROR);
147 : }
148 :
149 5469 : if (const ClusterStatusCode * status = std::get_if<ClusterStatusCode>(&mReturnStatus))
150 : {
151 5445 : return status->IsSuccess();
152 : }
153 :
154 24 : if (const ActionReturnStatus::FixedStatus * status = std::get_if<ActionReturnStatus::FixedStatus>(&mReturnStatus))
155 : {
156 24 : return (*status == ActionReturnStatus::FixedStatus::kWriteSuccessNoOp);
157 : }
158 :
159 : // all std::variant cases exhausted
160 0 : chipDie();
161 : }
162 :
163 79 : bool ActionReturnStatus::IsNoOpSuccess() const
164 : {
165 79 : if (const ActionReturnStatus::FixedStatus * status = std::get_if<ActionReturnStatus::FixedStatus>(&mReturnStatus))
166 : {
167 22 : 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 57 : 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 1590 : 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
|