3 * Copyright (c) 2020 Project CHIP Authors
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @file PigweedLogger.cpp
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.
27 #include <logging/log.h>
28 #include <logging/log_backend.h>
29 #include <logging/log_backend_std.h>
30 #include <logging/log_output.h>
33 #include <pw_hdlc/encoder.h>
34 #include <pw_stream/sys_io_stream.h>
35 #include <pw_sys_io_nrfconnect/init.h>
40 #include <string_view>
42 namespace PigweedLogger {
47 #if !CONFIG_LOG_MODE_IMMEDIATE
48 #error "Backend of Zephyr logger based on Pigweed HDLC requires LOG_MODE_IMMEDIATE=y"
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
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];
64 pw::hdlc::WriteUIFrame(kLogHdlcAddress, std::as_bytes(std::span(sWriteBuffer, sWriteBufferPos)), sWriter);
68 int putString(uint8_t * buffer, size_t size, void * /* ctx */)
70 assert(sWriteBufferPos < kWriteBufferSize);
72 for (size_t i = 0; i < size; ++i)
74 // Send each line excluding "\r\n" in a separate frame
76 if (buffer[i] == '\r')
79 if (buffer[i] == '\n')
85 sWriteBuffer[sWriteBufferPos++] = buffer[i];
87 if (sWriteBufferPos == kWriteBufferSize)
94 LOG_OUTPUT_DEFINE(pigweedLogOutput, putString, nullptr, 0);
101 void putMessageSync(const log_backend *, log_msg_ids srcLevel, uint32_t timestamp, const char * fmt, va_list args)
103 int ret = k_sem_take(&sLoggerLock, K_FOREVER);
107 log_backend_std_sync_string(&pigweedLogOutput, 0, srcLevel, timestamp, fmt, args);
109 k_sem_give(&sLoggerLock);
112 void putHexdumpSync(const log_backend *, log_msg_ids srcLevel, uint32_t timestamp, const char * metadata, const uint8_t * data,
115 int ret = k_sem_take(&sLoggerLock, K_FOREVER);
119 log_backend_std_sync_hexdump(&pigweedLogOutput, 0, srcLevel, timestamp, metadata, data, length);
121 k_sem_give(&sLoggerLock);
124 void panic(const log_backend *)
126 int ret = k_sem_take(&sLoggerLock, K_FOREVER);
129 log_backend_std_panic(&pigweedLogOutput);
133 k_sem_give(&sLoggerLock);
136 const log_backend_api pigweedLogApi = {
138 .put_sync_string = putMessageSync,
139 .put_sync_hexdump = putHexdumpSync,
144 LOG_BACKEND_DEFINE(pigweedLogBackend, pigweedLogApi, /* autostart */ true);
150 k_sem * GetSemaphore()
159 } // namespace PigweedLogger