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[inout]  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[inout]  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)
140 {
141     sLogInitialized = false;
142 }
143 
utilsLogRttOutput(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,va_list ap)144 void utilsLogRttOutput(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, va_list ap)
145 {
146     (void)aLogRegion;
147 
148     uint16_t length = 0;
149     int      charsWritten;
150     char     logString[LOG_PARSE_BUFFER_SIZE + 1];
151 
152     otEXPECT(sLogInitialized == true);
153 
154 #if (LOG_TIMESTAMP_ENABLE == 1)
155     length += logTimestamp(logString, LOG_PARSE_BUFFER_SIZE);
156 #endif
157 
158     // Add level information.
159     length += logLevel(&logString[length], (LOG_PARSE_BUFFER_SIZE - length), aLogLevel);
160 
161     charsWritten = vsnprintf(&logString[length], (size_t)(LOG_PARSE_BUFFER_SIZE - length), aFormat, ap);
162     otEXPECT(charsWritten >= 0);
163     length += charsWritten;
164 
165     if (length > LOG_PARSE_BUFFER_SIZE)
166     {
167         length = LOG_PARSE_BUFFER_SIZE;
168     }
169 
170     logString[length++] = '\n';
171 
172     // Write user log to the RTT memory block.
173     SEGGER_RTT_WriteNoLock(0, logString, length);
174 
175 exit:
176     return;
177 }
178 #endif // (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED)
179