Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / EFR32 / Logging.cpp
1 /* See Project CHIP LICENSE file for licensing information. */
2 #include <platform/logging/LogV.h>
3
4 #include <core/CHIPConfig.h>
5 #include <platform/CHIPDeviceConfig.h>
6
7 #include <support/SafeString.h>
8 #include <support/logging/CHIPLogging.h>
9
10 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
11 #include <openthread/platform/logging.h>
12 #endif
13
14 #include <FreeRTOS.h>
15 #include <queue.h>
16 #include <retargetserial.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <task.h>
20
21 #ifdef PW_RPC_ENABLED
22 #include "PigweedLogger.h"
23 #endif
24
25 // RTT Buffer size and name
26 #ifndef LOG_RTT_BUFFER_INDEX
27 #define LOG_RTT_BUFFER_INDEX 0
28 #endif
29
30 /**
31  * @def LOG_RTT_BUFFER_NAME
32  *
33  * RTT's name. Only used if LOG_RTT_BUFFER_INDEX is not 0. Otherwise,
34  * the buffer name is fixed to "Terminal".
35  *
36  */
37 #ifndef LOG_RTT_BUFFER_NAME
38 #define LOG_RTT_BUFFER_NAME "Terminal"
39 #endif
40
41 /**
42  * @def LOG_RTT_BUFFER_SIZE
43  *
44  * LOG RTT's buffer size. Only used if LOG_RTT_BUFFER_INDEX is not 0. To
45  * configure buffer #0 size, check the BUFFER_SIZE_UP definition in
46  * SEGGER_RTT_Conf.h
47  *
48  */
49 #ifndef LOG_RTT_BUFFER_SIZE
50 #define LOG_RTT_BUFFER_SIZE 256
51 #endif
52
53 // FreeRTOS includes
54 #include "SEGGER_RTT.h"
55 #include "SEGGER_RTT_Conf.h"
56
57 #define LOG_ERROR "<error > "
58 #define LOG_WARN "<warn  > "
59 #define LOG_INFO "<info  > "
60 #define LOG_DETAIL "<detail> "
61 #define LOG_LWIP "<lwip  > "
62 #define LOG_EFR32 "<efr32 > "
63 // If a new category string LOG_* is created, add it in the MaxStringLength arguments below
64 static constexpr size_t kMaxCategoryStrLen = chip::MaxStringLength(LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DETAIL, LOG_LWIP, LOG_EFR32);
65
66 #if EFR32_LOG_ENABLED
67 static bool sLogInitialized = false;
68 #endif
69 #if LOG_RTT_BUFFER_INDEX != 0
70 static uint8_t sLogBuffer[LOG_RTT_BUFFER_SIZE];
71 static uint8_t sCmdLineBuffer[LOG_RTT_BUFFER_SIZE];
72 #endif
73
74 #if EFR32_LOG_ENABLED
75 /**
76  * Print a log message to RTT
77  */
78 static void PrintLog(const char * msg)
79 {
80     if (sLogInitialized)
81     {
82         size_t sz;
83         sz = strlen(msg);
84         SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, msg, sz);
85 #ifdef PW_RPC_ENABLED
86         PigweedLogger::putString(msg, sz);
87 #endif
88
89         const char * newline = "\r\n";
90         sz                   = strlen(newline);
91         SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, newline, sz);
92 #ifdef PW_RPC_ENABLED
93         PigweedLogger::putString(newline, sz);
94 #endif
95     }
96 }
97 #endif // EFR32_LOG_ENABLED
98
99 /**
100  * Initialize Segger RTT for logging
101  */
102 extern "C" void efr32LogInit(void)
103 {
104 #if EFR32_LOG_ENABLED
105 #if LOG_RTT_BUFFER_INDEX != 0
106     SEGGER_RTT_ConfigUpBuffer(LOG_RTT_BUFFER_INDEX, LOG_RTT_BUFFER_NAME, sLogBuffer, LOG_RTT_BUFFER_SIZE,
107                               SEGGER_RTT_MODE_NO_BLOCK_TRIM);
108
109     SEGGER_RTT_ConfigDownBuffer(LOG_RTT_BUFFER_INDEX, LOG_RTT_BUFFER_NAME, sCmdLineBuffer, LOG_RTT_BUFFER_SIZE,
110                                 SEGGER_RTT_MODE_NO_BLOCK_SKIP);
111 #else
112     SEGGER_RTT_SetFlagsUpBuffer(LOG_RTT_BUFFER_INDEX, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
113 #endif
114
115 #ifdef PW_RPC_ENABLED
116     PigweedLogger::init();
117 #endif
118     sLogInitialized = true;
119 #endif // EFR32_LOG_ENABLED
120 }
121
122 /**
123  * General-purpose logging function
124  */
125 extern "C" void efr32Log(const char * aFormat, ...)
126 {
127     va_list v;
128
129     va_start(v, aFormat);
130 #if EFR32_LOG_ENABLED
131     char formattedMsg[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
132     static_assert(sizeof(formattedMsg) > kMaxCategoryStrLen); // Greater than to at least accommodate a ending Null Character
133
134     strcpy(formattedMsg, LOG_EFR32);
135     size_t prefixLen = strlen(formattedMsg);
136     size_t len       = vsnprintf(formattedMsg + prefixLen, sizeof formattedMsg - prefixLen, aFormat, v);
137
138     if (len >= sizeof formattedMsg - prefixLen)
139     {
140         formattedMsg[sizeof formattedMsg - 1] = '\0';
141     }
142
143     PrintLog(formattedMsg);
144 #endif // EFR32_LOG_ENABLED
145
146     va_end(v);
147 }
148
149 namespace chip {
150 namespace DeviceLayer {
151
152 /**
153  * Called whenever a log message is emitted by Chip or LwIP.
154  *
155  * This function is intended be overridden by the application to, e.g.,
156  * schedule output of queued log entries.
157  */
158 void __attribute__((weak)) OnLogOutput(void) {}
159
160 } // namespace DeviceLayer
161 } // namespace chip
162
163 namespace chip {
164 namespace Logging {
165 namespace Platform {
166
167 /**
168  * CHIP log output functions.
169  */
170 void LogV(const char * module, uint8_t category, const char * aFormat, va_list v)
171 {
172 #if EFR32_LOG_ENABLED && _CHIP_USE_LOGGING
173     if (IsCategoryEnabled(category))
174     {
175         char formattedMsg[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
176         size_t formattedMsgLen;
177
178         // len for Category string + "[" + Module name + "] " (Brackets and space =3)
179         constexpr size_t maxPrefixLen = kMaxCategoryStrLen + chip::Logging::kMaxModuleNameLen + 3;
180         static_assert(sizeof(formattedMsg) > maxPrefixLen); // Greater than to at least accommodate a ending Null Character
181
182         switch (category)
183         {
184         case kLogCategory_Error:
185             strcpy(formattedMsg, LOG_ERROR);
186             break;
187         case kLogCategory_Progress:
188         default:
189             strcpy(formattedMsg, LOG_INFO);
190             break;
191         case kLogCategory_Detail:
192             strcpy(formattedMsg, LOG_DETAIL);
193             break;
194         }
195
196         formattedMsgLen = strlen(formattedMsg);
197
198         // Form the log prefix, e.g. "[DL] "
199         snprintf(formattedMsg + formattedMsgLen, sizeof(formattedMsg) - formattedMsgLen, "[%s] ", module);
200         formattedMsg[sizeof(formattedMsg) - 1] = 0;
201         formattedMsgLen                        = strlen(formattedMsg);
202
203         size_t len = vsnprintf(formattedMsg + formattedMsgLen, sizeof formattedMsg - formattedMsgLen, aFormat, v);
204
205         if (len >= sizeof formattedMsg - formattedMsgLen)
206         {
207             formattedMsg[sizeof formattedMsg - 1] = '\0';
208         }
209
210         PrintLog(formattedMsg);
211     }
212
213     // Let the application know that a log message has been emitted.
214     chip::DeviceLayer::OnLogOutput();
215 #endif // EFR32_LOG_ENABLED && _CHIP_USE_LOGGING
216 }
217
218 } // namespace Platform
219 } // namespace Logging
220 } // namespace chip
221
222 /**
223  * LwIP log output function.
224  */
225 extern "C" void LwIPLog(const char * aFormat, ...)
226 {
227     va_list v;
228
229     va_start(v, aFormat);
230 #if EFR32_LOG_ENABLED
231     char formattedMsg[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
232
233     strcpy(formattedMsg, LOG_LWIP);
234     size_t prefixLen = strlen(formattedMsg);
235     size_t len       = vsnprintf(formattedMsg + prefixLen, sizeof formattedMsg - prefixLen, aFormat, v);
236
237     if (len >= sizeof formattedMsg - prefixLen)
238     {
239         formattedMsg[sizeof formattedMsg - 1] = '\0';
240     }
241
242     PrintLog(formattedMsg);
243
244 #if configCHECK_FOR_STACK_OVERFLOW
245     // Force a stack overflow check.
246     if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
247         taskYIELD();
248 #endif
249
250     // Let the application know that a log message has been emitted.
251     chip::DeviceLayer::OnLogOutput();
252 #endif // EFR32_LOG_ENABLED
253     va_end(v);
254 }
255
256 /**
257  * Platform logging function for OpenThread
258  */
259 #if CHIP_DEVICE_CONFIG_ENABLE_THREAD
260 extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char * aFormat, ...)
261 {
262     (void) aLogRegion;
263     va_list v;
264
265     va_start(v, aFormat);
266 #if EFR32_LOG_ENABLED
267     char formattedMsg[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
268
269     if (sLogInitialized)
270     {
271         switch (aLogLevel)
272         {
273         case OT_LOG_LEVEL_CRIT:
274             strcpy(formattedMsg, LOG_ERROR "[ot] ");
275             break;
276         case OT_LOG_LEVEL_WARN:
277             strcpy(formattedMsg, LOG_WARN "[ot] ");
278             break;
279         case OT_LOG_LEVEL_NOTE:
280             strcpy(formattedMsg, LOG_INFO "[ot] ");
281             break;
282         case OT_LOG_LEVEL_INFO:
283             strcpy(formattedMsg, LOG_INFO "[ot] ");
284             break;
285         case OT_LOG_LEVEL_DEBG:
286             strcpy(formattedMsg, LOG_DETAIL "[ot] ");
287             break;
288         default:
289             strcpy(formattedMsg, LOG_DETAIL "[ot] ");
290             break;
291         }
292
293         size_t prefixLen = strlen(formattedMsg);
294         size_t len       = vsnprintf(formattedMsg + prefixLen, sizeof(formattedMsg) - prefixLen, aFormat, v);
295
296         if (len >= sizeof formattedMsg - prefixLen)
297         {
298             formattedMsg[sizeof formattedMsg - 1] = '\0';
299         }
300
301         PrintLog(formattedMsg);
302
303 #if configCHECK_FOR_STACK_OVERFLOW
304         // Force a stack overflow check.
305         if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
306             taskYIELD();
307 #endif
308     }
309
310     // Let the application know that a log message has been emitted.
311     chip::DeviceLayer::OnLogOutput();
312 #endif // EFR32_LOG_ENABLED
313     va_end(v);
314 }
315 #endif // CHIP_ENABLE_OPENTHREAD
316
317 #if HARD_FAULT_LOG_ENABLE && EFR32_LOG_ENABLED
318
319 /**
320  * Log register contents to UART when a hard fault occurs.
321  */
322 extern "C" void debugHardfault(uint32_t * sp)
323 {
324     uint32_t cfsr  = SCB->CFSR;
325     uint32_t hfsr  = SCB->HFSR;
326     uint32_t mmfar = SCB->MMFAR;
327     uint32_t bfar  = SCB->BFAR;
328     uint32_t r0    = sp[0];
329     uint32_t r1    = sp[1];
330     uint32_t r2    = sp[2];
331     uint32_t r3    = sp[3];
332     uint32_t r12   = sp[4];
333     uint32_t lr    = sp[5];
334     uint32_t pc    = sp[6];
335     uint32_t psr   = sp[7];
336     char formattedMsg[32];
337
338     if (sLogInitialized == false)
339     {
340         efr32LogInit();
341     }
342
343     snprintf(formattedMsg, sizeof formattedMsg, LOG_ERROR "HardFault:\n");
344     PrintLog(formattedMsg);
345     snprintf(formattedMsg, sizeof formattedMsg, "SCB->CFSR   0x%08lx", cfsr);
346     PrintLog(formattedMsg);
347     snprintf(formattedMsg, sizeof formattedMsg, "SCB->HFSR   0x%08lx", hfsr);
348     PrintLog(formattedMsg);
349     snprintf(formattedMsg, sizeof formattedMsg, "SCB->MMFAR  0x%08lx", mmfar);
350     PrintLog(formattedMsg);
351     snprintf(formattedMsg, sizeof formattedMsg, "SCB->BFAR   0x%08lx", bfar);
352     PrintLog(formattedMsg);
353     snprintf(formattedMsg, sizeof formattedMsg, "SP          0x%08lx", (uint32_t) sp);
354     PrintLog(formattedMsg);
355     snprintf(formattedMsg, sizeof formattedMsg, "R0          0x%08lx\n", r0);
356     PrintLog(formattedMsg);
357     snprintf(formattedMsg, sizeof formattedMsg, "R1          0x%08lx\n", r1);
358     PrintLog(formattedMsg);
359     snprintf(formattedMsg, sizeof formattedMsg, "R2          0x%08lx\n", r2);
360     PrintLog(formattedMsg);
361     snprintf(formattedMsg, sizeof formattedMsg, "R3          0x%08lx\n", r3);
362     PrintLog(formattedMsg);
363     snprintf(formattedMsg, sizeof formattedMsg, "R12         0x%08lx\n", r12);
364     PrintLog(formattedMsg);
365     snprintf(formattedMsg, sizeof formattedMsg, "LR          0x%08lx\n", lr);
366     PrintLog(formattedMsg);
367     snprintf(formattedMsg, sizeof formattedMsg, "PC          0x%08lx\n", pc);
368     PrintLog(formattedMsg);
369     snprintf(formattedMsg, sizeof formattedMsg, "PSR         0x%08lx\n", psr);
370     PrintLog(formattedMsg);
371
372     while (1)
373         ;
374 }
375
376 /**
377  * Override default hard-fault handler
378  */
379 extern "C" __attribute__((naked)) void HardFault_Handler(void)
380 {
381     __asm volatile("tst lr, #4                                    \n"
382                    "ite eq                                        \n"
383                    "mrseq r0, msp                                 \n"
384                    "mrsne r0, psp                                 \n"
385                    "ldr r1, debugHardfault_address                \n"
386                    "bx r1                                         \n"
387                    "debugHardfault_address: .word debugHardfault  \n");
388 }
389
390 #endif // HARD_FAULT_LOG_ENABLE && EFR32_LOG_ENABLED