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