Line data Source code
1 : /**
2 : *
3 : * Copyright (c) 2020-2021 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 message helper functions in CHIP interaction model
21 : *
22 : */
23 :
24 : #include "MessageDefHelper.h"
25 : #include <algorithm>
26 : #include <app/AppConfig.h>
27 : #include <app/InteractionModelRevision.h>
28 : #include <app/util/basic-types.h>
29 : #include <inttypes.h>
30 : #include <lib/support/logging/CHIPLogging.h>
31 : #include <stdarg.h>
32 : #include <stdio.h>
33 :
34 : namespace chip {
35 : namespace app {
36 : #if CHIP_CONFIG_IM_PRETTY_PRINT && CHIP_DETAIL_LOGGING
37 : // this is used to run in signle thread for IM message debug purpose
38 : namespace {
39 : uint32_t gPrettyPrintingDepthLevel = 0;
40 : char gLineBuffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
41 : size_t gCurLineBufferSize = 0;
42 : } // namespace
43 :
44 313207 : void PrettyPrintIMBlankLine()
45 : {
46 313207 : if (gCurLineBufferSize)
47 : {
48 : // Don't need to explicitly NULL-terminate the string because
49 : // snprintf takes care of that.
50 305456 : ChipLogDetail(DataManagement, "%s", gLineBuffer);
51 305456 : gCurLineBufferSize = 0;
52 : }
53 :
54 1137867 : for (uint32_t i = 0; i < gPrettyPrintingDepthLevel; i++)
55 : {
56 824660 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
57 : {
58 824660 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
59 824660 : size_t ret = (size_t) (snprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, "\t"));
60 824660 : if (ret > 0)
61 : {
62 824660 : gCurLineBufferSize += std::min(ret, sizeLeft);
63 : }
64 : }
65 : }
66 313207 : }
67 :
68 1832426 : void PrettyPrintIM(bool aIsNewLine, const char * aFmt, ...)
69 : {
70 : va_list args;
71 1832426 : va_start(args, aFmt);
72 :
73 1832426 : if (aIsNewLine)
74 : {
75 278376 : PrettyPrintIMBlankLine();
76 : }
77 :
78 1832426 : if (sizeof(gLineBuffer) > gCurLineBufferSize)
79 : {
80 793636 : size_t sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
81 793636 : size_t ret = (size_t) (vsnprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, aFmt, args));
82 793636 : if (ret > 0)
83 : {
84 793636 : gCurLineBufferSize += std::min(ret, sizeLeft);
85 : }
86 : }
87 :
88 1832426 : va_end(args);
89 1832426 : }
90 73380 : void IncreaseDepth()
91 : {
92 73380 : gPrettyPrintingDepthLevel++;
93 73380 : }
94 :
95 73379 : void DecreaseDepth()
96 : {
97 73379 : gPrettyPrintingDepthLevel--;
98 73379 : }
99 : #endif
100 :
101 : #if CHIP_CONFIG_IM_PRETTY_PRINT
102 34851 : CHIP_ERROR CheckIMPayload(TLV::TLVReader & aReader, int aDepth, const char * aLabel)
103 : {
104 34851 : if (aDepth == 0)
105 : {
106 7565 : PRETTY_PRINT("%s = ", aLabel);
107 : }
108 : else
109 : {
110 27286 : if (TLV::IsContextTag(aReader.GetTag()))
111 : {
112 23073 : PRETTY_PRINT("0x%" PRIx32 " = ", TLV::TagNumFromTag(aReader.GetTag()));
113 : }
114 4213 : else if (TLV::IsProfileTag(aReader.GetTag()))
115 : {
116 0 : PRETTY_PRINT("0x%" PRIx32 "::0x%" PRIx32 " = ", TLV::ProfileIdFromTag(aReader.GetTag()),
117 : TLV::TagNumFromTag(aReader.GetTag()));
118 : }
119 : else
120 : {
121 : // Anonymous tag, don't print anything
122 : }
123 : }
124 :
125 34851 : switch (aReader.GetType())
126 : {
127 3803 : case TLV::kTLVType_Structure:
128 3803 : PRETTY_PRINT("{");
129 3803 : break;
130 :
131 4851 : case TLV::kTLVType_Array:
132 4851 : PRETTY_PRINT_SAMELINE("[");
133 4851 : PRETTY_PRINT("\t\t");
134 4851 : break;
135 :
136 90 : case TLV::kTLVType_SignedInteger: {
137 : int64_t value_s64;
138 :
139 90 : ReturnErrorOnFailure(aReader.Get(value_s64));
140 :
141 : // TODO: Figure out how to not use PRId64 here, since it's not supported
142 : // on all libcs.
143 90 : PRETTY_PRINT_SAMELINE("%" PRId64 ", ", value_s64);
144 90 : break;
145 : }
146 :
147 13412 : case TLV::kTLVType_UnsignedInteger: {
148 : uint64_t value_u64;
149 :
150 13412 : ReturnErrorOnFailure(aReader.Get(value_u64));
151 :
152 : // TODO: Figure out how to not use PRIu64 here, since it's not supported
153 : // on all libcs.
154 13412 : PRETTY_PRINT_SAMELINE("%" PRIu64 ", ", value_u64);
155 13412 : break;
156 : }
157 :
158 3112 : case TLV::kTLVType_FloatingPointNumber: {
159 : double value_fp;
160 :
161 3112 : ReturnErrorOnFailure(aReader.Get(value_fp));
162 :
163 3112 : PRETTY_PRINT_SAMELINE("%f, ", value_fp);
164 3112 : break;
165 : }
166 3268 : case TLV::kTLVType_Boolean: {
167 : bool value_b;
168 :
169 3268 : ReturnErrorOnFailure(aReader.Get(value_b));
170 :
171 3268 : PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
172 3268 : break;
173 : }
174 :
175 1562 : case TLV::kTLVType_UTF8String: {
176 : char value_s[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
177 :
178 : #if CHIP_DETAIL_LOGGING
179 1562 : uint32_t readerLen = aReader.GetLength();
180 : #endif // CHIP_DETAIL_LOGGING
181 1562 : CHIP_ERROR err = aReader.GetString(value_s, sizeof(value_s));
182 1562 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
183 :
184 1562 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
185 : {
186 0 : PRETTY_PRINT_SAMELINE("... (char string too long: %" PRIu32 " chars) ...", readerLen);
187 : }
188 : else
189 : {
190 1562 : PRETTY_PRINT_SAMELINE("\"%s\" (%" PRIu32 " chars), ", value_s, readerLen);
191 : }
192 1562 : break;
193 : }
194 :
195 4742 : case TLV::kTLVType_ByteString: {
196 : uint8_t value_b[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
197 : uint32_t len, readerLen;
198 :
199 4742 : readerLen = aReader.GetLength();
200 :
201 4742 : CHIP_ERROR err = aReader.GetBytes(value_b, sizeof(value_b));
202 4742 : VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, err);
203 :
204 4742 : PRETTY_PRINT_SAMELINE("[");
205 4742 : PRETTY_PRINT("\t\t");
206 :
207 4742 : if (readerLen < sizeof(value_b))
208 : {
209 4742 : len = readerLen;
210 : }
211 : else
212 : {
213 0 : len = sizeof(value_b);
214 : }
215 :
216 4742 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
217 : {
218 0 : PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
219 : }
220 : else
221 : {
222 1527744 : for (size_t i = 0; i < len; i++)
223 : {
224 1523002 : PRETTY_PRINT_SAMELINE("0x%02x, ", value_b[i]);
225 : }
226 : }
227 :
228 4742 : PRETTY_PRINT("] (%" PRIu32 " bytes)", readerLen);
229 4742 : break;
230 : }
231 :
232 11 : case TLV::kTLVType_Null:
233 11 : PRETTY_PRINT_SAMELINE("NULL");
234 11 : break;
235 :
236 0 : default:
237 0 : PRETTY_PRINT_SAMELINE("--");
238 0 : break;
239 : }
240 :
241 34851 : if (aReader.GetType() == TLV::kTLVType_Structure || aReader.GetType() == TLV::kTLVType_Array)
242 : {
243 8654 : const char terminating_char = (aReader.GetType() == TLV::kTLVType_Structure) ? '}' : ']';
244 : TLV::TLVType type;
245 :
246 : IgnoreUnusedVariable(terminating_char);
247 :
248 8654 : ReturnErrorOnFailure(aReader.EnterContainer(type));
249 :
250 : CHIP_ERROR err;
251 35940 : while ((err = aReader.Next()) == CHIP_NO_ERROR)
252 : {
253 27286 : PRETTY_PRINT_INCDEPTH();
254 :
255 27286 : ReturnErrorOnFailure(CheckIMPayload(aReader, aDepth + 1, aLabel));
256 :
257 27286 : PRETTY_PRINT_DECDEPTH();
258 : }
259 :
260 8654 : PRETTY_PRINT("%c,", terminating_char);
261 :
262 8654 : ReturnErrorOnFailure(aReader.ExitContainer(type));
263 : }
264 :
265 34851 : return CHIP_NO_ERROR;
266 : }
267 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
268 :
269 : }; // namespace app
270 : }; // namespace chip
|