Line data Source code
1 : /**
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2018 Google LLC.
5 : * Copyright (c) 2016-2017 Nest Labs, Inc.
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : /**
19 : * @file
20 : * This file defines Status Information Block in Interaction Model
21 : *
22 : */
23 :
24 : #include "StatusIB.h"
25 :
26 : #include "MessageDefHelper.h"
27 : #include "protocols/interaction_model/StatusCode.h"
28 :
29 : #include <inttypes.h>
30 : #include <stdarg.h>
31 : #include <stdio.h>
32 :
33 : #include <app/AppConfig.h>
34 : #include <lib/core/CHIPCore.h>
35 :
36 : using namespace chip;
37 : using namespace chip::TLV;
38 : using namespace chip::Protocols::InteractionModel;
39 :
40 : namespace chip {
41 : namespace app {
42 2515 : CHIP_ERROR StatusIB::Parser::DecodeStatusIB(StatusIB & aStatusIB) const
43 : {
44 2515 : TLV::TLVReader reader;
45 2515 : reader.Init(mReader);
46 5034 : while (CHIP_NO_ERROR == reader.Next())
47 : {
48 2519 : if (!TLV::IsContextTag(reader.GetTag()))
49 : {
50 0 : continue;
51 : }
52 2519 : switch (TLV::TagNumFromTag(reader.GetTag()))
53 : {
54 2515 : case to_underlying(Tag::kStatus):
55 2515 : ReturnErrorOnFailure(reader.Get(aStatusIB.mStatus));
56 2519 : break;
57 4 : case to_underlying(Tag::kClusterStatus):
58 : ClusterStatus clusterStatus;
59 4 : ReturnErrorOnFailure(reader.Get(clusterStatus));
60 4 : aStatusIB.mClusterStatus.SetValue(clusterStatus);
61 4 : break;
62 : }
63 : }
64 2515 : return CHIP_NO_ERROR;
65 : }
66 : #if CHIP_CONFIG_IM_PRETTY_PRINT
67 2521 : CHIP_ERROR StatusIB::Parser::PrettyPrint() const
68 : {
69 2521 : CHIP_ERROR err = CHIP_NO_ERROR;
70 2521 : TLV::TLVReader reader;
71 :
72 2521 : PRETTY_PRINT("StatusIB =");
73 2521 : PRETTY_PRINT("{");
74 :
75 : // make a copy of the reader
76 2521 : reader.Init(mReader);
77 5046 : while (CHIP_NO_ERROR == (err = reader.Next()))
78 : {
79 2525 : if (!TLV::IsContextTag(reader.GetTag()))
80 : {
81 0 : continue;
82 : }
83 2525 : uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag());
84 2525 : switch (tagNum)
85 : {
86 2521 : case to_underlying(Tag::kStatus):
87 : #if CHIP_DETAIL_LOGGING
88 : {
89 : uint8_t status;
90 2521 : ReturnErrorOnFailure(reader.Get(status));
91 2521 : PRETTY_PRINT("\tstatus = " ChipLogFormatIMStatus ",", ChipLogValueIMStatus(static_cast<Status>(status)));
92 : }
93 : #endif // CHIP_DETAIL_LOGGING
94 2521 : break;
95 4 : case to_underlying(Tag::kClusterStatus):
96 : #if CHIP_DETAIL_LOGGING
97 : {
98 : ClusterStatus clusterStatus;
99 4 : ReturnErrorOnFailure(reader.Get(clusterStatus));
100 4 : PRETTY_PRINT("\tcluster-status = 0x%x,", clusterStatus);
101 : }
102 : #endif // CHIP_DETAIL_LOGGING
103 4 : break;
104 0 : default:
105 0 : PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum);
106 0 : break;
107 : }
108 : }
109 :
110 2521 : PRETTY_PRINT("},");
111 2521 : PRETTY_PRINT_BLANK_LINE();
112 : // if we have exhausted this container
113 2521 : if (CHIP_END_OF_TLV == err)
114 : {
115 2521 : err = CHIP_NO_ERROR;
116 : }
117 2521 : ReturnErrorOnFailure(err);
118 2521 : return reader.ExitContainer(mOuterContainerType);
119 : }
120 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
121 :
122 2548 : StatusIB::Builder & StatusIB::Builder::EncodeStatusIB(const StatusIB & aStatusIB)
123 : {
124 2548 : mError = mpWriter->Put(TLV::ContextTag(Tag::kStatus), aStatusIB.mStatus);
125 2548 : SuccessOrExit(mError);
126 :
127 2548 : if (aStatusIB.mClusterStatus.HasValue())
128 : {
129 4 : mError = mpWriter->Put(TLV::ContextTag(Tag::kClusterStatus), aStatusIB.mClusterStatus.Value());
130 4 : SuccessOrExit(mError);
131 : }
132 :
133 2548 : EndOfContainer();
134 2548 : exit:
135 2548 : return *this;
136 : }
137 :
138 1337 : CHIP_ERROR StatusIB::ToChipError() const
139 : {
140 1337 : if (mStatus == Status::Success)
141 : {
142 1217 : return CHIP_NO_ERROR;
143 : }
144 :
145 120 : if (mClusterStatus.HasValue())
146 : {
147 4 : return ChipError(ChipError::SdkPart::kIMClusterStatus, mClusterStatus.Value());
148 : }
149 :
150 116 : return ChipError(ChipError::SdkPart::kIMGlobalStatus, to_underlying(mStatus));
151 : }
152 :
153 : namespace {
154 495 : bool FormatStatusIBError(char * buf, uint16_t bufSize, CHIP_ERROR err)
155 : {
156 495 : if (!err.IsIMStatus())
157 : {
158 408 : return false;
159 : }
160 :
161 87 : const char * desc = nullptr;
162 : #if !CHIP_CONFIG_SHORT_ERROR_STR
163 : static constexpr char generalFormat[] = "General error: " ChipLogFormatIMStatus;
164 : static constexpr char clusterFormat[] = "Cluster-specific error: 0x%02x";
165 :
166 : // Formatting an 8-bit int will take at most 2 chars, and replace the '%02x'
167 : // so a buffer big enough to hold our format string will also hold our
168 : // formatted string, as long as we account for the possible string formats.
169 87 : constexpr size_t statusNameMaxLength =
170 : #define CHIP_IM_STATUS_CODE(name, spec_name, value) \
171 : std::max(sizeof(#spec_name),
172 : #include <protocols/interaction_model/StatusCodeList.h>
173 : #undef CHIP_IM_STATUS_CODE
174 : static_cast<size_t>(0)
175 : #define CHIP_IM_STATUS_CODE(name, spec_name, value) \
176 : )
177 : #include <protocols/interaction_model/StatusCodeList.h>
178 : #undef CHIP_IM_STATUS_CODE
179 : ;
180 87 : constexpr size_t formattedSize = std::max(sizeof(generalFormat) + statusNameMaxLength, sizeof(clusterFormat));
181 : char formattedString[formattedSize];
182 :
183 87 : StatusIB status(err);
184 87 : if (status.mClusterStatus.HasValue())
185 : {
186 3 : snprintf(formattedString, formattedSize, clusterFormat, status.mClusterStatus.Value());
187 : }
188 : else
189 : {
190 84 : snprintf(formattedString, formattedSize, generalFormat, ChipLogValueIMStatus(status.mStatus));
191 : }
192 87 : desc = formattedString;
193 : #endif // !CHIP_CONFIG_SHORT_ERROR_STR
194 87 : FormatError(buf, bufSize, "IM", err, desc);
195 :
196 87 : return true;
197 : }
198 : } // anonymous namespace
199 :
200 407 : void StatusIB::RegisterErrorFormatter()
201 : {
202 : static ErrorFormatter sStatusIBErrorFormatter = { FormatStatusIBError, nullptr };
203 :
204 407 : ::RegisterErrorFormatter(&sStatusIBErrorFormatter);
205 407 : }
206 :
207 : }; // namespace app
208 : }; // namespace chip
|