Line data Source code
1 : /** 2 : * 3 : * Copyright (c) 2021 Project CHIP Authors 4 : * Licensed under the Apache License, Version 2.0 (the "License"); 5 : * you may not use this file except in compliance with the License. 6 : * You may obtain a copy of the License at 7 : * 8 : * http://www.apache.org/licenses/LICENSE-2.0 9 : * 10 : * Unless required by applicable law or agreed to in writing, software 11 : * distributed under the License is distributed on an "AS IS" BASIS, 12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 : * See the License for the specific language governing permissions and 14 : * limitations under the License. 15 : */ 16 : 17 : #include <inttypes.h> 18 : #include <stdarg.h> 19 : #include <stdio.h> 20 : 21 : #include "InvokeResponseMessage.h" 22 : #include "MessageDefHelper.h" 23 : 24 : #include <app/AppConfig.h> 25 : 26 : namespace chip { 27 : namespace app { 28 : #if CHIP_CONFIG_IM_PRETTY_PRINT 29 25 : CHIP_ERROR InvokeResponseMessage::Parser::PrettyPrint() const 30 : { 31 25 : CHIP_ERROR err = CHIP_NO_ERROR; 32 : TLV::TLVReader reader; 33 : 34 25 : PRETTY_PRINT("InvokeResponseMessage ="); 35 25 : PRETTY_PRINT("{"); 36 : 37 : // make a copy of the reader 38 25 : reader.Init(mReader); 39 : 40 101 : while (CHIP_NO_ERROR == (err = reader.Next())) 41 : { 42 76 : if (!TLV::IsContextTag(reader.GetTag())) 43 : { 44 0 : continue; 45 : } 46 76 : uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag()); 47 76 : switch (tagNum) 48 : { 49 25 : case to_underlying(Tag::kSuppressResponse): 50 : #if CHIP_DETAIL_LOGGING 51 : { 52 : bool suppressResponse; 53 25 : ReturnErrorOnFailure(reader.Get(suppressResponse)); 54 25 : PRETTY_PRINT("\tsuppressResponse = %s, ", suppressResponse ? "true" : "false"); 55 : } 56 : #endif // CHIP_DETAIL_LOGGING 57 25 : break; 58 25 : case to_underlying(Tag::kInvokeResponses): { 59 25 : InvokeResponseIBs::Parser invokeResponses; 60 25 : ReturnErrorOnFailure(invokeResponses.Init(reader)); 61 : 62 25 : PRETTY_PRINT_INCDEPTH(); 63 25 : ReturnErrorOnFailure(invokeResponses.PrettyPrint()); 64 25 : PRETTY_PRINT_DECDEPTH(); 65 : } 66 25 : break; 67 1 : case to_underlying(Tag::kMoreChunkedMessages): 68 : #if CHIP_DETAIL_LOGGING 69 : { 70 : bool moreChunkedMessages; 71 1 : ReturnErrorOnFailure(reader.Get(moreChunkedMessages)); 72 1 : PRETTY_PRINT("\tmoreChunkedMessages = %s, ", moreChunkedMessages ? "true" : "false"); 73 : } 74 : #endif // CHIP_DETAIL_LOGGING 75 1 : break; 76 25 : case kInteractionModelRevisionTag: 77 25 : ReturnErrorOnFailure(MessageParser::CheckInteractionModelRevision(reader)); 78 25 : break; 79 0 : default: 80 0 : PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum); 81 0 : break; 82 : } 83 : } 84 : 85 25 : PRETTY_PRINT("},"); 86 25 : PRETTY_PRINT_BLANK_LINE(); 87 : 88 25 : if (CHIP_END_OF_TLV == err) 89 : { 90 25 : err = CHIP_NO_ERROR; 91 : } 92 : 93 25 : ReturnErrorOnFailure(err); 94 25 : return reader.ExitContainer(mOuterContainerType); 95 : } 96 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT 97 : 98 25 : CHIP_ERROR InvokeResponseMessage::Parser::GetSuppressResponse(bool * const apSuppressResponse) const 99 : { 100 25 : return GetSimpleValue(to_underlying(Tag::kSuppressResponse), TLV::kTLVType_Boolean, apSuppressResponse); 101 : } 102 : 103 24 : CHIP_ERROR InvokeResponseMessage::Parser::GetInvokeResponses(InvokeResponseIBs::Parser * const apStatus) const 104 : { 105 : TLV::TLVReader reader; 106 24 : ReturnErrorOnFailure(mReader.FindElementWithTag(TLV::ContextTag(Tag::kInvokeResponses), reader)); 107 24 : return apStatus->Init(reader); 108 : } 109 : 110 25 : CHIP_ERROR InvokeResponseMessage::Parser::GetMoreChunkedMessages(bool * const apMoreChunkedMessages) const 111 : { 112 25 : return GetSimpleValue(to_underlying(Tag::kMoreChunkedMessages), TLV::kTLVType_Boolean, apMoreChunkedMessages); 113 : } 114 : 115 49 : CHIP_ERROR InvokeResponseMessage::Builder::InitWithEndBufferReserved(TLV::TLVWriter * const apWriter) 116 : { 117 49 : ReturnErrorOnFailure(Init(apWriter)); 118 49 : ReturnErrorOnFailure(GetWriter()->ReserveBuffer(GetSizeToEndInvokeResponseMessage())); 119 49 : mIsEndBufferReserved = true; 120 49 : return CHIP_NO_ERROR; 121 : } 122 : 123 49 : InvokeResponseMessage::Builder & InvokeResponseMessage::Builder::SuppressResponse(const bool aSuppressResponse) 124 : { 125 49 : if (mError == CHIP_NO_ERROR) 126 : { 127 49 : mError = mpWriter->PutBoolean(TLV::ContextTag(Tag::kSuppressResponse), aSuppressResponse); 128 : } 129 49 : return *this; 130 : } 131 : 132 50 : InvokeResponseIBs::Builder & InvokeResponseMessage::Builder::CreateInvokeResponses(const bool aReserveEndBuffer) 133 : { 134 50 : if (mError == CHIP_NO_ERROR) 135 : { 136 50 : if (aReserveEndBuffer) 137 : { 138 47 : mError = mInvokeResponses.InitWithEndBufferReserved(mpWriter, to_underlying(Tag::kInvokeResponses)); 139 : } 140 : else 141 : { 142 3 : mError = mInvokeResponses.Init(mpWriter, to_underlying(Tag::kInvokeResponses)); 143 : } 144 : } 145 50 : return mInvokeResponses; 146 : } 147 : 148 7 : InvokeResponseMessage::Builder & InvokeResponseMessage::Builder::MoreChunkedMessages(const bool aMoreChunkedMessages) 149 : { 150 : // If any changes are made to how we encoded MoreChunkedMessage that involves how many 151 : // bytes are needed, a corresponding change to GetSizeForMoreChunkResponses indicating 152 : // the new size that will be required. 153 : 154 : // skip if error has already been set 155 7 : SuccessOrExit(mError); 156 : 157 7 : if (mIsMoreChunkMessageBufferReserved) 158 : { 159 6 : mError = GetWriter()->UnreserveBuffer(GetSizeForMoreChunkResponses()); 160 6 : SuccessOrExit(mError); 161 6 : mIsMoreChunkMessageBufferReserved = false; 162 : } 163 : 164 7 : mError = mpWriter->PutBoolean(TLV::ContextTag(Tag::kMoreChunkedMessages), aMoreChunkedMessages); 165 7 : exit: 166 7 : return *this; 167 : } 168 : 169 11 : CHIP_ERROR InvokeResponseMessage::Builder::ReserveSpaceForMoreChunkedMessages() 170 : { 171 11 : ReturnErrorOnFailure(GetWriter()->ReserveBuffer(GetSizeForMoreChunkResponses())); 172 11 : mIsMoreChunkMessageBufferReserved = true; 173 11 : return CHIP_NO_ERROR; 174 : } 175 : 176 43 : CHIP_ERROR InvokeResponseMessage::Builder::EndOfInvokeResponseMessage() 177 : { 178 : // If any changes are made to how we end the invoke response message that involves how many 179 : // bytes are needed, a corresponding change to GetSizeToEndInvokeResponseMessage indicating 180 : // the new size that will be required. 181 43 : ReturnErrorOnFailure(mError); 182 43 : if (mIsEndBufferReserved) 183 : { 184 40 : ReturnErrorOnFailure(GetWriter()->UnreserveBuffer(GetSizeToEndInvokeResponseMessage())); 185 40 : mIsEndBufferReserved = false; 186 : } 187 43 : if (mError == CHIP_NO_ERROR) 188 : { 189 43 : mError = MessageBuilder::EncodeInteractionModelRevision(); 190 : } 191 43 : if (mError == CHIP_NO_ERROR) 192 : { 193 43 : EndOfContainer(); 194 : } 195 43 : return GetError(); 196 : } 197 : 198 17 : uint32_t InvokeResponseMessage::Builder::GetSizeForMoreChunkResponses() 199 : { 200 : // MoreChunkedMessages() encodes a uint8_t with context tag 0x02. This means 1 control byte, 201 : // 1 byte for the tag. For booleans the value is encoded in control byte. 202 17 : uint32_t kEncodeMoreChunkedMessages = 1 + 1; 203 : 204 17 : return kEncodeMoreChunkedMessages; 205 : } 206 : 207 89 : uint32_t InvokeResponseMessage::Builder::GetSizeToEndInvokeResponseMessage() 208 : { 209 : // EncodeInteractionModelRevision() encodes a uint8_t with context tag 0xFF. This means 1 control byte, 210 : // 1 byte for the tag, 1 byte for the value. 211 89 : uint32_t kEncodeInteractionModelSize = 1 + 1 + 1; 212 89 : uint32_t kEndOfContainerSize = 1; 213 : 214 89 : return kEncodeInteractionModelSize + kEndOfContainerSize; 215 : } 216 : } // namespace app 217 : } // namespace chip