From b1c7098c54d4ffee577aacb02b0194a762899351 Mon Sep 17 00:00:00 2001 From: Bruce Meagher Date: Tue, 12 Jul 2022 20:51:53 -0700 Subject: [PATCH] Initial version of log history support. --- platforms/common/CMakeLists.txt | 1 + .../common/include/px4_platform_common/log.h | 1 + .../include/px4_platform_common/log_history.h | 68 ++++++++ platforms/common/px4_log.cpp | 57 +++++++ platforms/common/px4_log_history.cpp | 147 ++++++++++++++++++ src/systemcmds/hist/CMakeLists.txt | 38 +++++ src/systemcmds/hist/Kconfig | 5 + src/systemcmds/hist/hist.cpp | 63 ++++++++ 8 files changed, 380 insertions(+) create mode 100644 platforms/common/include/px4_platform_common/log_history.h create mode 100644 platforms/common/px4_log_history.cpp create mode 100644 src/systemcmds/hist/CMakeLists.txt create mode 100644 src/systemcmds/hist/Kconfig create mode 100644 src/systemcmds/hist/hist.cpp diff --git a/platforms/common/CMakeLists.txt b/platforms/common/CMakeLists.txt index 82493344ae..892ee1a0d4 100644 --- a/platforms/common/CMakeLists.txt +++ b/platforms/common/CMakeLists.txt @@ -36,6 +36,7 @@ set(SRCS) if(NOT "${PX4_BOARD}" MATCHES "io-v2" AND NOT "${PX4_BOARD_LABEL}" MATCHES "bootloader") list(APPEND SRCS px4_log.cpp + px4_log_history.cpp ) endif() diff --git a/platforms/common/include/px4_platform_common/log.h b/platforms/common/include/px4_platform_common/log.h index dfbb562e37..7eacbd844e 100644 --- a/platforms/common/include/px4_platform_common/log.h +++ b/platforms/common/include/px4_platform_common/log.h @@ -130,6 +130,7 @@ __EXPORT void px4_log_modulename(int level, const char *moduleName, const char * __attribute__((format(printf, 3, 4))); __EXPORT void px4_log_raw(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +__EXPORT void px4_log_history(FILE *out); #if __GNUC__ // Allow empty format strings. diff --git a/platforms/common/include/px4_platform_common/log_history.h b/platforms/common/include/px4_platform_common/log_history.h new file mode 100644 index 0000000000..4153412836 --- /dev/null +++ b/platforms/common/include/px4_platform_common/log_history.h @@ -0,0 +1,68 @@ +/**************************************************************************** + * + * Copyright (C) 2022 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#pragma once + +#include + +#if defined(BOARD_ENABLE_LOG_HISTORY) +#include +#include + +#ifndef BOARD_LOG_HISTORY_SIZE +#define BOARD_LOG_HISTORY_SIZE (1024*4) // default buffer size +#endif + +class LogHistory +{ +public: + LogHistory() { px4_sem_init(&_lock, 0, 1); } + ~LogHistory() { px4_sem_destroy(&_lock); } + + void write(const char *buffer); + void print(FILE *out); + +private: + void lock() { do {} while (px4_sem_wait(&_lock) != 0); } + void unlock() { px4_sem_post(&_lock); } + + int size(); + int read(char *buffer, int buffer_length, int *offset); + + char _log_history[BOARD_LOG_HISTORY_SIZE]; + int _head{0}; + int _tail{0}; + px4_sem_t _lock; +}; + +#endif diff --git a/platforms/common/px4_log.cpp b/platforms/common/px4_log.cpp index 28cc92f3ca..8e733b5ee4 100644 --- a/platforms/common/px4_log.cpp +++ b/platforms/common/px4_log.cpp @@ -41,6 +41,7 @@ #endif #include +#include #if defined(__PX4_POSIX) #include #endif @@ -50,6 +51,10 @@ #include #include +#if defined(BOARD_ENABLE_LOG_HISTORY) +static LogHistory g_log_history; +#endif + static orb_advert_t orb_log_message_pub = nullptr; __EXPORT const char *__px4_log_level_str[_PX4_LOG_LEVEL_PANIC + 1] = { "DEBUG", "INFO", "WARN", "ERROR", "PANIC" }; @@ -146,6 +151,25 @@ __EXPORT void px4_log_modulename(int level, const char *module_name, const char fputs(buf, out); +#if defined(BOARD_ENABLE_LOG_HISTORY) + +#if defined(PX4_LOG_COLORIZED_OUTPUT) + + // No color formatting for log history + if (use_color) { + pos = snprintf(buf, max_length, __px4__log_level_fmt, __px4_log_level_str[level]); + pos += snprintf(buf + pos, math::max(max_length - pos, (ssize_t)0), __px4__log_modulename_pfmt, module_name); + va_start(argptr, fmt); + pos += vsnprintf(buf + pos, math::max(max_length - pos, (ssize_t)0), fmt, argptr); + va_end(argptr); + pos += sprintf(buf + math::min(pos, max_length - (ssize_t)1), "\n"); + buf[max_length] = 0; // ensure NULL termination + } + +#endif + g_log_history.write(buf); +#endif // BOARD_ENABLE_LOG_HISTORY + #if defined(CONFIG_ARCH_BOARD_PX4_SITL) // Without flushing it's tricky to see stdout output when PX4 is started by // a script like for the MAVSDK tests. @@ -227,5 +251,38 @@ __EXPORT void px4_log_raw(int level, const char *fmt, ...) buf[max_length] = 0; fputs(buf, out); + +#if defined(BOARD_ENABLE_LOG_HISTORY) + +#if defined(PX4_LOG_COLORIZED_OUTPUT) + + // No color formatting for log history + if (use_color) { + va_start(argptr, fmt); + pos = vsnprintf(buf, max_length, fmt, argptr); + va_end(argptr); + + if (pos > max_length) { + // preserve newline if necessary + if (fmt[strlen(fmt) - 1] == '\n') { + buf[max_length - 1] = '\n'; + } + } + + buf[max_length] = 0; // ensure NULL termination + } + +#endif + g_log_history.write(buf); +#endif // BOARD_ENABLE_LOG_HISTORY } } + +__EXPORT void px4_log_history(FILE *out) +{ + +#if defined(BOARD_ENABLE_LOG_HISTORY) + + g_log_history.print(out); +#endif // BOARD_ENABLE_LOG_HISTORY +} diff --git a/platforms/common/px4_log_history.cpp b/platforms/common/px4_log_history.cpp new file mode 100644 index 0000000000..2f63d98c54 --- /dev/null +++ b/platforms/common/px4_log_history.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** + * + * Copyright (C) 2022 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include + +#if defined(BOARD_ENABLE_LOG_HISTORY) +#include + +void LogHistory::print(FILE *out) +{ + const int buffer_length = 512; + char buffer[buffer_length]; + int offset = -1; + + int total_size_read = 0; + + do { + int read_size = read(buffer, buffer_length, &offset); + + if (read_size <= 0) { + break; + } + + fwrite(buffer, 1, read_size, out); + + if (read_size < buffer_length) { + break; + } + + total_size_read += read_size; + } while (total_size_read < BOARD_LOG_HISTORY_SIZE); +} + +// Log a null terminated string to the circular history buffer. +void LogHistory::write(const char *buffer) +{ + lock(); // same rule as for printf: this cannot be used from IRQ handlers + + int i = 0; + + while (buffer[i] != '\0') { + + _log_history[_tail] = buffer[i++]; + _tail = (_tail + 1) % BOARD_LOG_HISTORY_SIZE; + + if (_tail == _head) { + _head = (_head + 1) % BOARD_LOG_HISTORY_SIZE; + } + } + + unlock(); +} + +int LogHistory::size() +{ + lock(); + int size; + + if (_head <= _tail) { + size = _tail - _head; + + } else { + size = BOARD_LOG_HISTORY_SIZE - (_head - _tail); + } + + unlock(); + return size; +} + +int LogHistory::read(char *buffer, int buffer_length, int *offset) +{ + lock(); + + if (*offset == -1) { + *offset = _head; + } + + int size = 0; + + if (*offset < _tail) { + size = _tail - *offset; + + if (size > buffer_length) { + size = buffer_length; + } + + memcpy(buffer, _log_history + *offset, size); + + } else if (_tail < *offset) { + size = BOARD_LOG_HISTORY_SIZE - *offset; + + if (size > buffer_length) { + size = buffer_length; + } + + memcpy(buffer, _log_history + *offset, size); + buffer += size; + buffer_length -= size; + + int size_secondary = _tail; + + if (size_secondary > buffer_length) { + size_secondary = buffer_length; + } + + if (size_secondary > 0) { + memcpy(buffer, _log_history, size_secondary); + size += size_secondary; + } + } + + unlock(); + *offset = (*offset + size) % BOARD_LOG_HISTORY_SIZE; + return size; +} + +#endif diff --git a/src/systemcmds/hist/CMakeLists.txt b/src/systemcmds/hist/CMakeLists.txt new file mode 100644 index 0000000000..d5237f6ab0 --- /dev/null +++ b/src/systemcmds/hist/CMakeLists.txt @@ -0,0 +1,38 @@ +############################################################################ +# +# Copyright (c) 2022 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ +px4_add_module( + MODULE systemcmds__hist + MAIN hist + SRCS + hist.cpp + ) diff --git a/src/systemcmds/hist/Kconfig b/src/systemcmds/hist/Kconfig new file mode 100644 index 0000000000..fb742a456f --- /dev/null +++ b/src/systemcmds/hist/Kconfig @@ -0,0 +1,5 @@ +menuconfig SYSTEMCMDS_HIST + bool "hist" + default n + ---help--- + Enable support for hist diff --git a/src/systemcmds/hist/hist.cpp b/src/systemcmds/hist/hist.cpp new file mode 100644 index 0000000000..a81db44385 --- /dev/null +++ b/src/systemcmds/hist/hist.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** + * + * Copyright (c) 2022 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include +#include +#include + +#ifndef BOARD_ENABLE_LOG_HISTORY +#error "This module can only be used on boards that enable BOARD_ENABLE_LOG_HISTORY" +#endif + +extern "C" { + __EXPORT int hist_main(int argc, char *argv[]); +} + +static void usage() +{ + PRINT_MODULE_DESCRIPTION("Command-line tool to show the px4 message history. There are no arguments."); + PRINT_MODULE_USAGE_NAME_SIMPLE("hist", "command"); +} + + +int hist_main(int argc, char *argv[]) +{ + if (argc > 1) { + usage(); + return 0; + } + + px4_log_history(stdout); + + return 0; +}