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 : 28 : #include <inttypes.h> 29 : #include <stdarg.h> 30 : #include <stdio.h> 31 : 32 : #include <app/AppConfig.h> 33 : #include <lib/core/CHIPCore.h> 34 : 35 : using namespace chip; 36 : using namespace chip::TLV; 37 : using namespace chip::Protocols::InteractionModel; 38 : 39 : namespace chip { 40 : namespace app { 41 2782 : CHIP_ERROR StatusIB::Parser::DecodeStatusIB(StatusIB & aStatusIB) const 42 : { 43 : TLV::TLVReader reader; 44 2782 : reader.Init(mReader); 45 5566 : while (CHIP_NO_ERROR == reader.Next()) 46 : { 47 2784 : if (!TLV::IsContextTag(reader.GetTag())) 48 : { 49 0 : continue; 50 : } 51 2784 : switch (TLV::TagNumFromTag(reader.GetTag())) 52 : { 53 2782 : case to_underlying(Tag::kStatus): 54 2782 : ReturnErrorOnFailure(reader.Get(aStatusIB.mStatus)); 55 2784 : break; 56 2 : case to_underlying(Tag::kClusterStatus): 57 : ClusterStatus clusterStatus; 58 2 : ReturnErrorOnFailure(reader.Get(clusterStatus)); 59 2 : aStatusIB.mClusterStatus.SetValue(clusterStatus); 60 2 : break; 61 : } 62 : } 63 2782 : return CHIP_NO_ERROR; 64 : } 65 : #if CHIP_CONFIG_IM_PRETTY_PRINT 66 2788 : CHIP_ERROR StatusIB::Parser::PrettyPrint() const 67 : { 68 2788 : CHIP_ERROR err = CHIP_NO_ERROR; 69 : TLV::TLVReader reader; 70 : 71 2788 : PRETTY_PRINT("StatusIB ="); 72 2788 : PRETTY_PRINT("{"); 73 : 74 : // make a copy of the reader 75 2788 : reader.Init(mReader); 76 5578 : while (CHIP_NO_ERROR == (err = reader.Next())) 77 : { 78 2790 : if (!TLV::IsContextTag(reader.GetTag())) 79 : { 80 0 : continue; 81 : } 82 2790 : uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); 83 2790 : switch (tagNum) 84 : { 85 2788 : case to_underlying(Tag::kStatus): 86 : #if CHIP_DETAIL_LOGGING 87 : { 88 : uint8_t status; 89 2788 : ReturnErrorOnFailure(reader.Get(status)); 90 2788 : PRETTY_PRINT("\tstatus = " ChipLogFormatIMStatus ",", ChipLogValueIMStatus(static_cast<Status>(status))); 91 : } 92 : #endif // CHIP_DETAIL_LOGGING 93 2788 : break; 94 2 : case to_underlying(Tag::kClusterStatus): 95 : #if CHIP_DETAIL_LOGGING 96 : { 97 : ClusterStatus clusterStatus; 98 2 : ReturnErrorOnFailure(reader.Get(clusterStatus)); 99 2 : PRETTY_PRINT("\tcluster-status = 0x%x,", clusterStatus); 100 : } 101 : #endif // CHIP_DETAIL_LOGGING 102 2 : break; 103 0 : default: 104 0 : PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); 105 0 : break; 106 : } 107 : } 108 : 109 2788 : PRETTY_PRINT("},"); 110 2788 : PRETTY_PRINT_BLANK_LINE(); 111 : // if we have exhausted this container 112 2788 : if (CHIP_END_OF_TLV == err) 113 : { 114 2788 : err = CHIP_NO_ERROR; 115 : } 116 2788 : ReturnErrorOnFailure(err); 117 2788 : return reader.ExitContainer(mOuterContainerType); 118 : } 119 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT 120 : 121 2815 : StatusIB::Builder & StatusIB::Builder::EncodeStatusIB(const StatusIB & aStatusIB) 122 : { 123 2815 : mError = mpWriter->Put(TLV::ContextTag(Tag::kStatus), aStatusIB.mStatus); 124 2815 : SuccessOrExit(mError); 125 : 126 2815 : if (aStatusIB.mClusterStatus.HasValue()) 127 : { 128 2 : mError = mpWriter->Put(TLV::ContextTag(Tag::kClusterStatus), aStatusIB.mClusterStatus.Value()); 129 2 : SuccessOrExit(mError); 130 : } 131 : 132 2815 : EndOfContainer(); 133 2815 : exit: 134 2815 : return *this; 135 : } 136 : 137 1264 : CHIP_ERROR StatusIB::ToChipError() const 138 : { 139 1264 : if (mStatus == Status::Success) 140 : { 141 1146 : return CHIP_NO_ERROR; 142 : } 143 : 144 118 : if (mClusterStatus.HasValue()) 145 : { 146 4 : return ChipError(ChipError::SdkPart::kIMClusterStatus, mClusterStatus.Value()); 147 : } 148 : 149 114 : return ChipError(ChipError::SdkPart::kIMGlobalStatus, to_underlying(mStatus)); 150 : } 151 : 152 80 : void StatusIB::InitFromChipError(CHIP_ERROR aError) 153 : { 154 80 : if (aError.IsPart(ChipError::SdkPart::kIMClusterStatus)) 155 : { 156 4 : mStatus = Status::Failure; 157 4 : mClusterStatus = MakeOptional(aError.GetSdkCode()); 158 4 : return; 159 : } 160 : 161 76 : mClusterStatus = NullOptional; 162 76 : if (aError == CHIP_NO_ERROR) 163 : { 164 1 : mStatus = Status::Success; 165 1 : return; 166 : } 167 : 168 75 : if (aError.IsPart(ChipError::SdkPart::kIMGlobalStatus)) 169 : { 170 61 : mStatus = static_cast<Status>(aError.GetSdkCode()); 171 61 : return; 172 : } 173 : 174 14 : mStatus = Status::Failure; 175 : } 176 : 177 : namespace { 178 436 : bool FormatStatusIBError(char * buf, uint16_t bufSize, CHIP_ERROR err) 179 : { 180 436 : if (!err.IsIMStatus()) 181 : { 182 421 : return false; 183 : } 184 : 185 15 : const char * desc = nullptr; 186 : #if !CHIP_CONFIG_SHORT_ERROR_STR 187 : static constexpr char generalFormat[] = "General error: " ChipLogFormatIMStatus; 188 : static constexpr char clusterFormat[] = "Cluster-specific error: 0x%02x"; 189 : 190 : // Formatting an 8-bit int will take at most 2 chars, and replace the '%02x' 191 : // so a buffer big enough to hold our format string will also hold our 192 : // formatted string, as long as we account for the possible string formats. 193 15 : constexpr size_t statusNameMaxLength = 194 : #define CHIP_IM_STATUS_CODE(name, spec_name, value) \ 195 : max(sizeof(#spec_name), 196 : #include <protocols/interaction_model/StatusCodeList.h> 197 : #undef CHIP_IM_STATUS_CODE 198 : static_cast<size_t>(0) 199 : #define CHIP_IM_STATUS_CODE(name, spec_name, value) \ 200 : ) 201 : #include <protocols/interaction_model/StatusCodeList.h> 202 : #undef CHIP_IM_STATUS_CODE 203 : ; 204 15 : constexpr size_t formattedSize = max(sizeof(generalFormat) + statusNameMaxLength, sizeof(clusterFormat)); 205 : char formattedString[formattedSize]; 206 : 207 15 : StatusIB status; 208 15 : status.InitFromChipError(err); 209 15 : if (status.mClusterStatus.HasValue()) 210 : { 211 1 : snprintf(formattedString, formattedSize, clusterFormat, status.mClusterStatus.Value()); 212 : } 213 : else 214 : { 215 14 : snprintf(formattedString, formattedSize, generalFormat, ChipLogValueIMStatus(status.mStatus)); 216 : } 217 15 : desc = formattedString; 218 : #endif // !CHIP_CONFIG_SHORT_ERROR_STR 219 15 : FormatError(buf, bufSize, "IM", err, desc); 220 : 221 15 : return true; 222 15 : } 223 : } // anonymous namespace 224 : 225 368 : void StatusIB::RegisterErrorFormatter() 226 : { 227 : static ErrorFormatter sStatusIBErrorFormatter = { FormatStatusIBError, nullptr }; 228 : 229 368 : ::RegisterErrorFormatter(&sStatusIBErrorFormatter); 230 368 : } 231 : 232 : }; // namespace app 233 : }; // namespace chip