1 /*
2  *  Copyright (c) 2018, The OpenThread Authors.
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 are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements the OpenThread platform abstraction for logging.
32  *
33  */
34 
35 #include <openthread-core-config.h>
36 #include <openthread/config.h>
37 
38 #include <utils/code_utils.h>
39 #include <openthread/platform/alarm-milli.h>
40 #include <openthread/platform/logging.h>
41 
42 #include "SEGGER_RTT.h"
43 #include "logging_rtt.h"
44 
45 #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED)
46 #if (LOG_RTT_COLOR_ENABLE == 1)
47 #define RTT_COLOR_CODE_DEFAULT "\x1B[0m"
48 #define RTT_COLOR_CODE_RED "\x1B[1;31m"
49 #define RTT_COLOR_CODE_GREEN "\x1B[1;32m"
50 #define RTT_COLOR_CODE_YELLOW "\x1B[1;33m"
51 #define RTT_COLOR_CODE_CYAN "\x1B[1;36m"
52 #else // LOG_RTT_COLOR_ENABLE == 1
53 #define RTT_COLOR_CODE_DEFAULT ""
54 #define RTT_COLOR_CODE_RED ""
55 #define RTT_COLOR_CODE_GREEN ""
56 #define RTT_COLOR_CODE_YELLOW ""
57 #define RTT_COLOR_CODE_CYAN ""
58 #endif // LOG_RTT_COLOR_ENABLE == 1
59 
60 static bool sLogInitialized = false;
61 
62 #if LOG_RTT_BUFFER_INDEX != 0
63 static uint8_t sLogBuffer[LOG_RTT_BUFFER_SIZE];
64 #endif
65 
66 /**
67  * Function for getting color of a given level log.
68  *
69  * @param[in]  aLogLevel The log level.
70  *
71  * @returns  String with a log level color value.
72  */
levelToString(otLogLevel aLogLevel)73 static inline const char *levelToString(otLogLevel aLogLevel)
74 {
75     switch (aLogLevel)
76     {
77     case OT_LOG_LEVEL_CRIT:
78         return RTT_COLOR_CODE_RED;
79 
80     case OT_LOG_LEVEL_WARN:
81         return RTT_COLOR_CODE_YELLOW;
82 
83     case OT_LOG_LEVEL_INFO:
84         return RTT_COLOR_CODE_GREEN;
85 
86     case OT_LOG_LEVEL_DEBG:
87     default:
88         return RTT_COLOR_CODE_DEFAULT;
89     }
90 }
91 
92 #if (LOG_TIMESTAMP_ENABLE == 1)
93 /**
94  * Function for printing actual timestamp.
95  *
96  * @param[in,out]  aLogString Pointer to the log buffer.
97  * @param[in]      aMaxSize   Maximum size of the log buffer.
98  *
99  * @returns  Number of bytes successfully written to the log buffer.
100  */
logTimestamp(char * aLogString,uint16_t aMaxSize)101 static inline int logTimestamp(char *aLogString, uint16_t aMaxSize)
102 {
103     long unsigned int now = otPlatAlarmMilliGetNow();
104     return snprintf(aLogString, (size_t)aMaxSize, "%s[%010lu]", RTT_COLOR_CODE_CYAN, now);
105 }
106 #endif
107 
108 /**
109  * Function for printing log level.
110  *
111  * @param[in,out]  aLogString  Pointer to log buffer.
112  * @param[in]      aMaxSize    Maximum size of log buffer.
113  * @param[in]      aLogLevel   Log level.
114  *
115  * @returns  Number of bytes successfully written to the log buffer.
116  */
logLevel(char * aLogString,uint16_t aMaxSize,otLogLevel aLogLevel)117 static inline int logLevel(char *aLogString, uint16_t aMaxSize, otLogLevel aLogLevel)
118 {
119     return snprintf(aLogString, (size_t)aMaxSize, "%s ", levelToString(aLogLevel));
120 }
121 
utilsLogRttInit(void)122 void utilsLogRttInit(void)
123 {
124 #if LOG_RTT_BUFFER_INDEX != 0
125     int res = SEGGER_RTT_ConfigUpBuffer(LOG_RTT_BUFFER_INDEX, LOG_RTT_BUFFER_NAME, sLogBuffer, LOG_RTT_BUFFER_SIZE,
126                                         SEGGER_RTT_MODE_NO_BLOCK_TRIM);
127 #else
128     int res = SEGGER_RTT_SetFlagsUpBuffer(LOG_RTT_BUFFER_INDEX, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
129 #endif
130 
131     otEXPECT(res >= 0);
132 
133     sLogInitialized = true;
134 
135 exit:
136     return;
137 }
138 
utilsLogRttDeinit(void)139 void utilsLogRttDeinit(void) { sLogInitialized = false; }
140 
utilsLogRttOutput(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,va_list ap)141 void utilsLogRttOutput(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, va_list ap)
142 {
143     (void)aLogRegion;
144 
145     uint16_t length = 0;
146     int      charsWritten;
147     char     logString[LOG_PARSE_BUFFER_SIZE + 1];
148 
149     otEXPECT(sLogInitialized == true);
150 
151 #if (LOG_TIMESTAMP_ENABLE == 1)
152     length += logTimestamp(logString, LOG_PARSE_BUFFER_SIZE);
153 #endif
154 
155     // Add level information.
156     length += logLevel(&logString[length], (LOG_PARSE_BUFFER_SIZE - length), aLogLevel);
157 
158     charsWritten = vsnprintf(&logString[length], (size_t)(LOG_PARSE_BUFFER_SIZE - length), aFormat, ap);
159     otEXPECT(charsWritten >= 0);
160     length += charsWritten;
161 
162     if (length > LOG_PARSE_BUFFER_SIZE)
163     {
164         length = LOG_PARSE_BUFFER_SIZE;
165     }
166 
167     logString[length++] = '\n';
168 
169     // Write user log to the RTT memory block.
170     SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, logString, length);
171 
172 exit:
173     return;
174 }
175 #endif // (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED)
176