Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / platform / nrfconnect / util / PigweedLogger.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    All rights reserved.
5  *
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 /*
20  * @file PigweedLogger.cpp
21  *
22  * This file contains a backend of Zephyr logging system, based on Pigweed HDLC
23  * over UART transport. It allows to send log messages even if the application
24  * needs to use HDLC/UART for another purpose like the RPC server.
25  */
26
27 #include <logging/log.h>
28 #include <logging/log_backend.h>
29 #include <logging/log_backend_std.h>
30 #include <logging/log_output.h>
31 #include <zephyr.h>
32
33 #include <pw_hdlc/encoder.h>
34 #include <pw_stream/sys_io_stream.h>
35 #include <pw_sys_io_nrfconnect/init.h>
36
37 #include <cassert>
38 #include <cstdint>
39 #include <span>
40 #include <string_view>
41
42 namespace PigweedLogger {
43 namespace {
44
45 #if CONFIG_LOG
46
47 #if !CONFIG_LOG_MODE_IMMEDIATE
48 #error "Backend of Zephyr logger based on Pigweed HDLC requires LOG_MODE_IMMEDIATE=y"
49 #endif
50
51 constexpr uint8_t kLogHdlcAddress = 1;   // Send log messages to HDLC address 1 (other than RPC communication)
52 constexpr size_t kWriteBufferSize = 128; // Buffer for constructing HDLC frames
53
54 // Exclusive access to the backend is needed to make sure that log messages coming
55 // from different threads are not interwoven.
56 K_SEM_DEFINE(sLoggerLock, 1, 1);
57 pw::stream::SysIoWriter sWriter;
58 size_t sWriteBufferPos;
59 uint8_t sWriteBuffer[kWriteBufferSize];
60 bool sIsPanicMode;
61
62 void flush()
63 {
64     pw::hdlc::WriteUIFrame(kLogHdlcAddress, std::as_bytes(std::span(sWriteBuffer, sWriteBufferPos)), sWriter);
65     sWriteBufferPos = 0;
66 }
67
68 int putString(uint8_t * buffer, size_t size, void * /* ctx */)
69 {
70     assert(sWriteBufferPos < kWriteBufferSize);
71
72     for (size_t i = 0; i < size; ++i)
73     {
74         // Send each line excluding "\r\n" in a separate frame
75
76         if (buffer[i] == '\r')
77             continue;
78
79         if (buffer[i] == '\n')
80         {
81             flush();
82             continue;
83         }
84
85         sWriteBuffer[sWriteBufferPos++] = buffer[i];
86
87         if (sWriteBufferPos == kWriteBufferSize)
88             flush();
89     }
90
91     return size;
92 }
93
94 LOG_OUTPUT_DEFINE(pigweedLogOutput, putString, nullptr, 0);
95
96 void init()
97 {
98     pw_sys_io_Init();
99 }
100
101 void putMessageSync(const log_backend *, log_msg_ids srcLevel, uint32_t timestamp, const char * fmt, va_list args)
102 {
103     int ret = k_sem_take(&sLoggerLock, K_FOREVER);
104     assert(ret == 0);
105
106     if (!sIsPanicMode)
107         log_backend_std_sync_string(&pigweedLogOutput, 0, srcLevel, timestamp, fmt, args);
108
109     k_sem_give(&sLoggerLock);
110 }
111
112 void putHexdumpSync(const log_backend *, log_msg_ids srcLevel, uint32_t timestamp, const char * metadata, const uint8_t * data,
113                     uint32_t length)
114 {
115     int ret = k_sem_take(&sLoggerLock, K_FOREVER);
116     assert(ret == 0);
117
118     if (!sIsPanicMode)
119         log_backend_std_sync_hexdump(&pigweedLogOutput, 0, srcLevel, timestamp, metadata, data, length);
120
121     k_sem_give(&sLoggerLock);
122 }
123
124 void panic(const log_backend *)
125 {
126     int ret = k_sem_take(&sLoggerLock, K_FOREVER);
127     assert(ret == 0);
128
129     log_backend_std_panic(&pigweedLogOutput);
130     flush();
131     sIsPanicMode = true;
132
133     k_sem_give(&sLoggerLock);
134 }
135
136 const log_backend_api pigweedLogApi = {
137     .put              = nullptr,
138     .put_sync_string  = putMessageSync,
139     .put_sync_hexdump = putHexdumpSync,
140     .panic            = panic,
141     .init             = init,
142 };
143
144 LOG_BACKEND_DEFINE(pigweedLogBackend, pigweedLogApi, /* autostart */ true);
145
146 #endif // CONFIG_LOG
147
148 } // namespace
149
150 k_sem * GetSemaphore()
151 {
152 #if CONFIG_LOG
153     return &sLoggerLock;
154 #else
155     return nullptr;
156 #endif
157 }
158
159 } // namespace PigweedLogger