Line data Source code
1 : /*
2 : * Copyright (c) 2022 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 :
18 : #pragma once
19 :
20 : #include <limits>
21 : #include <type_traits>
22 :
23 : #include <stdint.h>
24 :
25 : #include <lib/core/CHIPConfig.h>
26 : #include <lib/core/DataModelTypes.h>
27 : #include <lib/core/Optional.h>
28 : #include <lib/support/TypeTraits.h>
29 :
30 : #if CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
31 : #define ChipLogFormatIMStatus "0x%02x (%s)"
32 : #define ChipLogValueIMStatus(status) chip::to_underlying(status), chip::Protocols::InteractionModel::StatusName(status)
33 : #else // CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
34 : #define ChipLogFormatIMStatus "0x%02x"
35 : #define ChipLogValueIMStatus(status) chip::to_underlying(status)
36 : #endif // CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
37 :
38 : namespace chip {
39 : namespace Protocols {
40 : namespace InteractionModel {
41 :
42 : enum class Status : uint8_t
43 : {
44 : #define CHIP_IM_STATUS_CODE(name, spec_name, value) name = value,
45 : #include <protocols/interaction_model/StatusCodeList.h>
46 : #undef CHIP_IM_STATUS_CODE
47 :
48 : InvalidValue = ConstraintError, // Deprecated
49 : };
50 :
51 : #if CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
52 : const char * StatusName(Status status);
53 : #endif // CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT
54 :
55 : /**
56 : * @brief Class to encapsulate a Status code, including possibly a
57 : * cluster-specific code for generic SUCCESS/FAILURE.
58 : *
59 : * This abstractions joins together Status and ClusterStatus, which
60 : * are the components of a StatusIB, used in many IM actions, in a
61 : * way which allows both of them to carry together.
62 : *
63 : * This class can only be directly constructed from a `Status`. To
64 : * attach a cluster-specific-code, please use the `ClusterSpecificFailure()`
65 : * and `ClusterSpecificSuccess()` factory methods.
66 : */
67 : class ClusterStatusCode
68 : {
69 : public:
70 81 : explicit ClusterStatusCode(Status status) : mStatus(status) {}
71 : explicit ClusterStatusCode(CHIP_ERROR err);
72 :
73 : // We only have simple copyable members, so we should be trivially copyable.
74 129 : ClusterStatusCode(const ClusterStatusCode & other) = default;
75 0 : ClusterStatusCode & operator=(const ClusterStatusCode & other) = default;
76 :
77 38 : bool operator==(const ClusterStatusCode & other) const
78 : {
79 66 : return (this->mStatus == other.mStatus) && (this->HasClusterSpecificCode() == other.HasClusterSpecificCode()) &&
80 66 : (this->GetClusterSpecificCode() == other.GetClusterSpecificCode());
81 : }
82 :
83 : bool operator!=(const ClusterStatusCode & other) const { return !(*this == other); }
84 :
85 : ClusterStatusCode & operator=(const Status & status)
86 : {
87 : this->mStatus = status;
88 : this->mClusterSpecificCode = chip::NullOptional;
89 : return *this;
90 : }
91 :
92 : /**
93 : * @brief Builder for a cluster-specific failure status code.
94 : *
95 : * @tparam T - enum type for the cluster-specific status code
96 : * (e.g. chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum)
97 : * @param cluster_specific_code - cluster-specific code to record with the failure
98 : * (e.g. chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kWindowNotOpen)
99 : * @return a ClusterStatusCode instance properly configured.
100 : */
101 : template <typename T, typename std::enable_if_t<std::is_enum<T>::value, bool> = true>
102 : static ClusterStatusCode ClusterSpecificFailure(T cluster_specific_code)
103 : {
104 : static_assert(std::numeric_limits<std::underlying_type_t<T>>::max() <= std::numeric_limits<ClusterStatus>::max(),
105 : "Type used must fit in uint8_t");
106 : return ClusterStatusCode(Status::Failure, chip::to_underlying(cluster_specific_code));
107 : }
108 :
109 2 : static ClusterStatusCode ClusterSpecificFailure(ClusterStatus cluster_specific_code)
110 : {
111 2 : return ClusterStatusCode(Status::Failure, cluster_specific_code);
112 : }
113 :
114 : /**
115 : * @brief Builder for a cluster-specific success status code.
116 : *
117 : * @tparam T - enum type for the cluster-specific status code
118 : * (e.g. chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum)
119 : * @param cluster_specific_code - cluster-specific code to record with the success
120 : * (e.g. chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kBasicWindowOpen)
121 : * @return a ClusterStatusCode instance properly configured.
122 : */
123 : template <typename T, typename std::enable_if_t<std::is_enum<T>::value, bool> = true>
124 : static ClusterStatusCode ClusterSpecificSuccess(T cluster_specific_code)
125 : {
126 : static_assert(std::numeric_limits<std::underlying_type_t<T>>::max() <= std::numeric_limits<ClusterStatus>::max(),
127 : "Type used must fit in uint8_t");
128 : return ClusterStatusCode(Status::Success, chip::to_underlying(cluster_specific_code));
129 : }
130 :
131 2 : static ClusterStatusCode ClusterSpecificSuccess(ClusterStatus cluster_specific_code)
132 : {
133 2 : return ClusterStatusCode(Status::Success, cluster_specific_code);
134 : }
135 :
136 : /// @return true if the core Status associated with this ClusterStatusCode is the one for success.
137 56 : bool IsSuccess() const { return mStatus == Status::Success; }
138 :
139 : /// @return the core Status code associated withi this ClusterStatusCode.
140 295 : Status GetStatus() const { return mStatus; }
141 :
142 : /// @return true if a cluster-specific code is associated with the ClusterStatusCode.
143 83 : bool HasClusterSpecificCode() const { return mClusterSpecificCode.HasValue(); }
144 :
145 : /// @return the cluster-specific code associated with this ClusterStatusCode or chip::NullOptional if none is associated.
146 270 : chip::Optional<ClusterStatus> GetClusterSpecificCode() const
147 : {
148 270 : if ((mStatus != Status::Failure) && (mStatus != Status::Success))
149 : {
150 153 : return chip::NullOptional;
151 : }
152 117 : return mClusterSpecificCode;
153 : }
154 :
155 : private:
156 : ClusterStatusCode() = delete;
157 4 : ClusterStatusCode(Status status, ClusterStatus cluster_specific_code) :
158 4 : mStatus(status), mClusterSpecificCode(chip::MakeOptional(cluster_specific_code))
159 4 : {}
160 :
161 : Status mStatus;
162 : chip::Optional<ClusterStatus> mClusterSpecificCode;
163 : };
164 :
165 : static_assert(sizeof(ClusterStatusCode) <= sizeof(uint32_t), "ClusterStatusCode must not grow to be larger than a uint32_t");
166 :
167 : } // namespace InteractionModel
168 : } // namespace Protocols
169 : } // namespace chip
|