1 /*
2 Copyright (c) 2018, MIPI Alliance, Inc.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * Neither the name of the copyright holder nor the names of its
18 contributors may be used to endorse or promote products derived
19 from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Contributors:
36 * Norbert Schulz (Intel Corporation) - Initial API and implementation
37 */
38
39 #include<sstream>
40 #include <iomanip>
41 #include "mipi_syst_message.h"
42 #include "mipi_syst_collateral.h"
43 #include "mipi_syst_printf.h"
44
45 MIPI_SYST_NAMESPACE_BEGIN
46
47 // Code for storing and printing out decoded message content
48 //
49
setLocAddr32(uint32_t addr)50 void message::setLocAddr32(uint32_t addr)
51 {
52 m_loc.tag |= location_type::ADDRESS32;
53 m_loc.tag &= ~location_type::ADDRESS64;
54 m_loc.address = addr;
55 }
56
setLocAddr64(uint64_t addr)57 void message::setLocAddr64(uint64_t addr)
58 {
59 m_loc.tag |= location_type::ADDRESS64;
60 m_loc.tag &= ~location_type::ADDRESS32;
61 m_loc.address = addr;
62 }
63
setLocFileLine(uint32_t file,uint32_t line)64 void message::setLocFileLine(uint32_t file, uint32_t line)
65 {
66 m_loc.tag |= location_type::IDANDLINE;
67 m_loc.file = file;
68 m_loc.line = line;
69 }
70
71 // Check type for short message
72 //
isShort(message::header hdr)73 bool message::isShort(message::header hdr) {
74 switch (hdr.field.type) {
75 case message::type::SHORT32:
76 case message::type::SHORT64:
77 return true;
78
79 case message::type::BUILD:
80 switch (hdr.field.subtype) {
81 case message::subtype_build::BUILD_COMPACT32:
82 case message::subtype_build::BUILD_COMPACT64:
83 return true;
84 }
85 }
86 return false;
87 }
88
89
90 // Pretty print decode status value
91 //
status2string(const message & msg)92 static const char * status2string(const message& msg)
93 {
94 switch (msg.getState()) {
95 case message::decode_state::OK:
96 return "OK";
97 case message::decode_state::UNKNOWN_TYPE:
98 return "UNKNOWN_TYPE";
99 case message::decode_state::TOO_SHORT:
100 return "TOO_SHORT";
101 case message::decode_state::CHECKSUM_ERROR:
102 return "CHECKSUM_ERROR";
103 case message::decode_state::MISSING_COLLATERAL:
104 return "MISSING_COLLATERAL";
105 default:
106 return "UNKNOWN_STATE";
107 }
108 }
109
110 // Pretty print sevrity values
111 //
112 static const char * severity2string[] = {
113 "MAX",
114 "FATAL",
115 "ERROR",
116 "WARNING",
117 "INFO",
118 "USER1",
119 "USER2",
120 "DEBUG"
121 };
122
123 // Pretty print type:subtype values
124 //
type2string(message::header hdr,const collateral * coll)125 static const std::string type2string(
126 message::header hdr,
127 const collateral * coll)
128 {
129 static const char * typenames[] = {
130 "BUILD",
131 "SHORT32",
132 "STRING",
133 "CATALOG",
134 "UNKNOWN(4)",
135 "UNKNOWN(5)",
136 "RAW",
137 "SHORT64",
138 "CLOCK",
139 "UNKNOWN(9)",
140 "UNKNOWN(10)",
141 "UNKNOWN(11)",
142 "UNKNOWN(12)",
143 "UNKNOWN(13)",
144 "UNKNOWN(14)",
145 "UNKNOWN(15)",
146 };
147
148 uint32_t type(hdr.field.type);
149 std::stringstream sstr;
150
151 sstr << typenames[type];
152
153 // compute subtype string
154 //
155 std::string subtype("??");
156
157 switch (type) {
158 case message::type::SHORT32:
159 case message::type::SHORT64:
160 subtype.clear(); // no subtype
161 break;
162
163 case message::type::BUILD:
164 switch (hdr.field.subtype) {
165 case message::subtype_build::BUILD_LONG:
166 subtype = "LONG";
167 break;
168 case message::subtype_build::BUILD_COMPACT32:
169 subtype = "COMPACT32";
170 break;
171 case message::subtype_build::BUILD_COMPACT64:
172 subtype = "COMPACT64";
173 break;
174 }
175 break;
176 case message::type::STRING:
177 switch (hdr.field.subtype) {
178 case message::subtype_string::STRING_GENERIC:
179 subtype = "GENERIC";
180 break;
181 case message::subtype_string::STRING_FUNCTIONENTER:
182 subtype = "ENTER";
183 break;
184 case message::subtype_string::STRING_FUNCTIONEXIT:
185 subtype = "EXIT";
186 break;
187 case message::subtype_string::STRING_INVALIDPARAM:
188 subtype = "INVPARAM";
189 break;
190 case message::subtype_string::STRING_ASSERT:
191 subtype = "ASSERT";
192 break;
193 case message::subtype_string::STRING_PRINTF_32:
194 subtype = "PRINTF32";
195 break;
196 case message::subtype_string::STRING_PRINTF_64:
197 subtype = "PRINTF64";
198 break;
199 }
200 break;
201 case message::type::CATALOG:
202 switch (hdr.field.subtype) {
203 case message::subtype_catalog::CATALOG_ID32_P32:
204 subtype = "ID32P32";
205 break;
206 case message::subtype_catalog::CATALOG_ID64_P32:
207 subtype = "ID64P32";
208 break;
209 case message::subtype_catalog::CATALOG_ID32_P64:
210 subtype = "ID32P64";
211 break;
212 case message::subtype_catalog::CATALOG_ID64_P64:
213 subtype = "ID64P64";
214 break;
215 }
216 break;
217 case message::type::RAW:
218 {
219 const std::string * name(nullptr);
220 if (coll && (name = coll->getWriteType(hdr.field.subtype)) != nullptr)
221 {
222 std::stringstream dest;
223 hostPrintf(dest, *name, hdr.field.subtype, std::vector<int>());
224 subtype = dest.str();
225 } else {
226 subtype = std::to_string(hdr.field.subtype);
227 }
228 } break;
229
230 case message::type::CLOCK:
231 switch (hdr.field.subtype) {
232 case message::subtype_clock::CLOCK_SYNC:
233 subtype = "SYNC";
234 break;
235 }
236 break;
237 }
238
239 if (!subtype.empty()) {
240 sstr << ':' << subtype;
241 }
242
243 return sstr.str();
244 }
245
246 // CSV double-quote escaping, replace " with "" and eliminate newlines
247 //
csvQuoteString(std::ostream & os,const std::string & s)248 void csvQuoteString(std::ostream& os, const std::string& s)
249 {
250 for (auto c : s) {
251 if (c == '\n') {
252 os << ' '; // newline not supported in CSV
253 } else if (c == '"') {
254 os << c << c;
255 } else {
256 os << c;
257 }
258 }
259 }
260
261 // location information printing
262 //
location2string(const message::location & loc,const collateral * collateral)263 std::string location2string(
264 const message::location& loc,
265 const collateral * collateral)
266 {
267 bool hasAddress(0!=(loc.tag & (message::ADDRESS32 | message::ADDRESS32)));
268 bool hasFileLine(0 != (loc.tag & message::IDANDLINE));
269
270 std::stringstream sstr;
271
272 if (hasFileLine) {
273 const std::string * fileName(
274 collateral != nullptr ?
275 collateral->getSourceFile(loc.file) : nullptr);
276
277 if (fileName != nullptr) {
278 sstr << (*fileName) << ':' << loc.line;
279 } else {
280 sstr << loc.file << ':' << loc.line;
281 }
282 if (hasAddress) sstr << ' ';
283 }
284
285 if (hasAddress) {
286 if (loc.tag & message::ADDRESS32) {
287 sstr << toHexValue((uint32_t)loc.address);
288 } else {
289 sstr << toHexValue(loc.address);
290 }
291 }
292
293 return sstr.str();
294 }
295 const char message::csvHeaderString[] = "Decode Status,Payload,Type,Severity,Origin,Unit,Message TimeStamp,Context TimeStamp,Location,Raw Length,Checksum,Collateral";
296
297 // CSV line formatting of a message
298 //
operator <<(std::ostream & os,const message & msg)299 std::ostream& operator << (std::ostream& os, const message& msg)
300 {
301 char delimiter(',');
302 const collateral * coll(msg.getCollateral());
303
304 // turn volatile fields like timestamp/crc off when running unit testing
305 //
306 static bool unit_testing(getenv("SYST_UNITTESTING") != NULL);
307
308 // status
309 os << status2string(msg) << delimiter;
310
311 // payload
312 os << '"';
313 csvQuoteString(os, msg.getPayload());
314 os << '"' << delimiter;
315
316 if (msg.getState() != message::OK && msg.getState() != message::MISSING_COLLATERAL)
317 {
318 // decode failed, report other fields as empty. The data can't be trusted.
319 //
320 os << ",,,,," << std::endl;
321 return os;
322 }
323
324 // Type/Subtype
325 //
326 os << type2string(msg.getHeader(), msg.getCollateral()) << delimiter;
327
328 // Severity
329 //
330 os << severity2string[msg.getHeader().field.severity] << delimiter;
331
332 // client name and unit
333 //
334 os << msg.getClientName() << delimiter;
335 os << msg.getUnit() << delimiter;
336
337 // time stamps
338 if (msg.getHeader().field.timestamp) {
339 os << (unit_testing ?
340 "<--UNITTEST-HIDE_TS-->" : toHexValue(msg.getMessageTS()));
341 }
342 os << delimiter;
343
344 os << (unit_testing ?
345 "<--UNITTEST-HIDE_TS-->" : toHexValue(msg.getContextTS())) << delimiter;
346
347 // location
348 //
349 csvQuoteString(os, location2string(msg.getLocation(), coll));
350 os << delimiter;
351
352 // raw message length
353 //
354 os << std::to_string(msg.getLength()) << delimiter;
355
356 // crc
357 //
358 if (msg.getHeader().field.chksum) {
359 os << (unit_testing ? "<--UNITTEST-HIDE_CRC-->" : toHexValue(msg.getCrc()));
360 }
361 os << delimiter;
362
363 if (coll != nullptr) {
364 csvQuoteString(os, coll->getFileName());
365 }
366 os << std::endl;
367
368 return os;
369 }
370
371 MIPI_SYST_NAMESPACE_END