From e28de03c88d396d2dc45afbc720c5e555d480526 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Thu, 17 Nov 2016 14:38:19 +0100 Subject: ucoo/utils: add trace dump without debuger --- ucoo/hal/i2c/i2c_hard.stm32.cc | 2 +- ucoo/hal/timer/timer.hh | 5 +++ ucoo/hal/usb/test/Makefile | 2 +- ucoo/hal/usb/usb_driver.cc | 2 +- ucoo/utils/Module | 2 +- ucoo/utils/trace.cc | 79 ++++++++++++++++++++++++++++++++++++++++++ ucoo/utils/trace.hh | 51 +++++++++++++++++++++++++-- ucoo/utils/trace.tcc | 48 +++++++++++++++++++++++-- 8 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 ucoo/utils/trace.cc diff --git a/ucoo/hal/i2c/i2c_hard.stm32.cc b/ucoo/hal/i2c/i2c_hard.stm32.cc index 22567c9..fa0266b 100644 --- a/ucoo/hal/i2c/i2c_hard.stm32.cc +++ b/ucoo/hal/i2c/i2c_hard.stm32.cc @@ -30,7 +30,7 @@ namespace ucoo { /// Local trace. -static Trace i2c_trace; +static Trace i2c_trace ("i2c"); /// Information on I2C hardware structure. struct i2c_hardware_t diff --git a/ucoo/hal/timer/timer.hh b/ucoo/hal/timer/timer.hh index ab0fa18..31f785f 100644 --- a/ucoo/hal/timer/timer.hh +++ b/ucoo/hal/timer/timer.hh @@ -23,6 +23,7 @@ // DEALINGS IN THE SOFTWARE. // // }}} +#include #if defined TARGET_stm32 # include "timer.stm32.hh" @@ -44,6 +45,10 @@ struct TimerTraceTimestamp { e.timestamp = Timer::get_value (); } + int dump (const Entry &e, const Entry &eprev, char *buf) const + { + return sprintf (buf, "[%+8d] ", static_cast (e.timestamp - eprev.timestamp)); + } }; } // namespace ucoo diff --git a/ucoo/hal/usb/test/Makefile b/ucoo/hal/usb/test/Makefile index d4849df..cac90d8 100644 --- a/ucoo/hal/usb/test/Makefile +++ b/ucoo/hal/usb/test/Makefile @@ -4,6 +4,6 @@ TARGETS = stm32f4 PROGS = test_usb test_usb_SOURCES = test_usb.cc -MODULES = ucoo/hal/usb ucoo/hal/gpio +MODULES = ucoo/hal/usb ucoo/hal/gpio ucoo/utils include $(BASE)/build/top.mk diff --git a/ucoo/hal/usb/usb_driver.cc b/ucoo/hal/usb/usb_driver.cc index efd8e6c..e53fe2f 100644 --- a/ucoo/hal/usb/usb_driver.cc +++ b/ucoo/hal/usb/usb_driver.cc @@ -26,7 +26,7 @@ namespace ucoo { -Trace usb_trace; +Trace usb_trace ("usb"); void UsbDriver::register_application (UsbApplication &app) diff --git a/ucoo/utils/Module b/ucoo/utils/Module index 1d101e4..4da0530 100644 --- a/ucoo/utils/Module +++ b/ucoo/utils/Module @@ -1 +1 @@ -ucoo_utils_SOURCES := delay.arm.cc crc.cc +ucoo_utils_SOURCES := delay.arm.cc crc.cc trace.cc diff --git a/ucoo/utils/trace.cc b/ucoo/utils/trace.cc new file mode 100644 index 0000000..27a99a8 --- /dev/null +++ b/ucoo/utils/trace.cc @@ -0,0 +1,79 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2016 Nicolas Schodet +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// }}} +#include "ucoo/utils/trace.hh" +#include + +namespace ucoo { + +void +TraceRegistry::register_trace_buffer (TraceBufferBase &b) +{ + TraceRegistry &self = get_instance (); + b.next_ = self.first; + self.first = &b; +} + +bool +TraceRegistry::dump_all (std::function + dump_callback) +{ + return dump (nullptr, dump_callback); +} + +bool +TraceRegistry::dump (const char *name, + std::function + dump_callback) +{ + bool ok = true; + TraceRegistry &self = get_instance (); + TraceBufferBase *b = self.first; + while (b) + { + if (!name || std::strcmp (name, b->name_) == 0) + { + { + char buf[128]; + int r = snprintf (buf, sizeof (buf) - 1, "---[%s]---", b->name_); + if (r >= static_cast (sizeof (buf) - 1)) + r = sizeof (buf) - 2; + buf[r++] = '\n'; + buf[r++] = '\0'; + ok = ok && dump_callback (buf, r); + } + ok = ok && b->dump (dump_callback); + } + b = b->next_; + } + return ok; +} + +TraceRegistry & +TraceRegistry::get_instance () +{ + static TraceRegistry instance; + return instance; +} + +} // namespace ucoo diff --git a/ucoo/utils/trace.hh b/ucoo/utils/trace.hh index 7cae33d..6c73593 100644 --- a/ucoo/utils/trace.hh +++ b/ucoo/utils/trace.hh @@ -23,6 +23,7 @@ // DEALINGS IN THE SOFTWARE. // // }}} +#include namespace ucoo { @@ -33,11 +34,28 @@ struct NoTimestamp struct Entry { }; /// Fill an entry with current timestamp. void operator () (Entry &) { } + /// Dump an entry timestamp, there is room for 32 characters, return the + /// dumped text length. + int dump (const Entry &e, const Entry &eprev, char *buf) const { return 0; } +}; + +/// Trace buffer common base. +class TraceBufferBase +{ + public: + /// Dump as text, call dump_callback several time with text dump. + virtual bool dump (std::function dump_callback) const = 0; + protected: + constexpr TraceBufferBase (const char *name) : name_ (name) { } + friend class TraceRegistry; + const char *name_; + TraceBufferBase *next_ = nullptr; }; /// Trace buffer to be read with debugger. template -class TraceBuffer +class TraceBuffer : public TraceBufferBase { /// Maximum number of arguments. static const int args_nb = 4; @@ -45,7 +63,7 @@ class TraceBuffer static const int entries_nb = 512; public: /// Constructor. - TraceBuffer (const Timestamp ×tamp = Timestamp ()); + TraceBuffer (const char *name, const Timestamp ×tamp = Timestamp ()); /// Trace without argument. inline void operator() (const char *str); /// Trace with N arguments... @@ -53,6 +71,9 @@ class TraceBuffer inline void operator() (const char *str, int a0, int a1); inline void operator() (const char *str, int a0, int a1, int a2); inline void operator() (const char *str, int a0, int a1, int a2, int a3); + /// See TraceBufferBase::dump. + bool dump (std::function dump_callback) const override; private: /// Trace entry, contains all given parameters. struct Entry : public Timestamp::Entry @@ -72,11 +93,15 @@ class TraceBuffer class TraceDummy { public: + TraceDummy (const char *name) { } inline void operator() (const char *str) { } inline void operator() (const char *str, int a0) { } inline void operator() (const char *str, int a0, int a1) { } inline void operator() (const char *str, int a0, int a1, int a2) { } inline void operator() (const char *str, int a0, int a1, int a2, int a3) { } + bool dump (std::function dump_callback) const + { return true; } }; /// Conditional trace, whether it trace or not depends on the template @@ -89,11 +114,33 @@ class Trace template class Trace : public TraceBuffer { + public: + constexpr Trace (const char *name) : TraceBuffer (name) { } }; template class Trace : public TraceDummy { + public: + constexpr Trace (const char *name) : TraceDummy (name) { } +}; + +/// Registry of all active traces. +class TraceRegistry +{ + public: + /// Register a trace buffer (called automatically on trace buffer + /// construction). + static void register_trace_buffer (TraceBufferBase &b); + /// Dump all active traces as text. + static bool dump_all (std::function dump_callback); + /// Dump specified trace as text. + static bool dump (const char *name, std::function dump_callback); + private: + static TraceRegistry &get_instance (); + TraceBufferBase *first = nullptr; }; } // namespace ucoo diff --git a/ucoo/utils/trace.tcc b/ucoo/utils/trace.tcc index 8d1fc29..1a64e8c 100644 --- a/ucoo/utils/trace.tcc +++ b/ucoo/utils/trace.tcc @@ -23,13 +23,17 @@ // DEALINGS IN THE SOFTWARE. // // }}} +#include namespace ucoo { template -TraceBuffer::TraceBuffer (const Timestamp ×tamp) - : entries{}, index (0), timestamp_ (timestamp) +TraceBuffer::TraceBuffer (const char *name, + const Timestamp ×tamp) + : TraceBufferBase (name), + entries{}, index (0), timestamp_ (timestamp) { + TraceRegistry::register_trace_buffer (*this); } template @@ -88,6 +92,46 @@ TraceBuffer::operator() (const char *str, int a0, int a1, int a2, index = (index + 1) % entries_nb; } +template +bool +TraceBuffer::dump (std::function dump_callback) const +{ + bool ok = true; + unsigned int i = index; + if (!entries[i].str) + i = 0; + if (entries[i].str) + { + unsigned int iprev = i; + do + { + char buf[128]; + int buf_size; + buf_size = timestamp_.dump (entries[i], entries[iprev], buf); + int r = snprintf (buf + buf_size, sizeof (buf) - buf_size - 1, + entries[i].str, + entries[i].args[0], entries[i].args[1], + entries[i].args[2], entries[i].args[3]); + if (r >= static_cast (sizeof (buf) - buf_size - 1)) + { + buf_size = sizeof (buf - 5); + buf[buf_size++] = '.'; + buf[buf_size++] = '.'; + buf[buf_size++] = '.'; + } + else + buf_size += r; + buf[buf_size++] = '\n'; + buf[buf_size++] = '\0'; + ok = ok && dump_callback (buf, buf_size); + iprev = i; + i = (i + 1) % entries_nb; + } while (i != index && ok); + } + return ok; +} + } // namespace ucoo #endif // ucoo_utils_trace_tcc -- cgit v1.2.3