From 7259a1356959ab9fb18472bfdeb45a2c88f864dd Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 3 Jun 2020 23:14:17 +0200 Subject: [PATCH] more improvements: 1. New optional flag to redirect print to stderr. THis can be useful on host environemtns (e.g linux) 2. non-buffered mode if this flag is true: the preamble msut be printed manually 2. Getter function for preamble for that case. 3. printChar function: specify whether to print to stderr or stdout --- serviceinterface/ServiceInterfaceBuffer.cpp | 94 ++++++++++++--------- serviceinterface/ServiceInterfaceBuffer.h | 50 ++++++++--- serviceinterface/ServiceInterfaceStream.cpp | 12 ++- serviceinterface/ServiceInterfaceStream.h | 37 ++++++-- 4 files changed, 131 insertions(+), 62 deletions(-) diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 2a97ab90b..93de88b39 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -3,9 +3,42 @@ #include // to be implemented by bsp -extern "C" void printChar(const char*); +extern "C" void printChar(const char*, bool errStream); + +#ifndef UT699 + +ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage, + bool errStream, bool addCrToPreamble, uint16_t port): + isActive(true), logMessage(setMessage), + addCrToPreamble(addCrToPreamble), errStream(errStream) { + if(not errStream) { + // Set pointers if the stream is buffered. + setp( buf, buf + BUF_SIZE ); + } +} + +void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { + char array[BUF_SIZE]; + uint32_t length = end - begin; + if (length > sizeof(array)) { + length = sizeof(array); + } + memcpy(array, begin, length); + + for(; begin != end; begin++){ + printChar(begin, false); + } +} + +#endif int ServiceInterfaceBuffer::overflow(int c) { + if(errStream and this->isActive) { + if (c != Traits::eof()) { + printChar(reinterpret_cast(&c), true); + } + return 0; + } // Handle output putChars(pbase(), pptr()); if (c != Traits::eof()) { @@ -20,53 +53,38 @@ int ServiceInterfaceBuffer::overflow(int c) { } int ServiceInterfaceBuffer::sync(void) { - if (this->isActive) { - Clock::TimeOfDay_t loggerTime; - Clock::getDateAndTime(&loggerTime); - std::string preamble; - if(addCrToPreamble) { - preamble += "\r"; + if(not this->isActive or errStream) { + if(not errStream) { + setp(buf, buf + BUF_SIZE - 1); } - preamble += log_message + ": | " + zero_padded(loggerTime.hour, 2) - + ":" + zero_padded(loggerTime.minute, 2) + ":" - + zero_padded(loggerTime.second, 2) + "." - + zero_padded(loggerTime.usecond/1000, 3) + " | "; - // Write log_message and time - this->putChars(preamble.c_str(), preamble.c_str() + preamble.size()); - // Handle output - this->putChars(pbase(), pptr()); + return 0; } + + auto preamble = getPreamble(); + // Write logMessage and time + this->putChars(preamble.c_str(), preamble.c_str() + preamble.size()); + // Handle output + this->putChars(pbase(), pptr()); // This tells that buffer is empty again setp(buf, buf + BUF_SIZE - 1); return 0; } - -#ifndef UT699 - -ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, - uint16_t port, bool addCrToPreamble) { - this->addCrToPreamble = addCrToPreamble; - this->log_message = set_message; - this->isActive = true; - setp( buf, buf + BUF_SIZE ); +std::string ServiceInterfaceBuffer::getPreamble() { + Clock::TimeOfDay_t loggerTime; + Clock::getDateAndTime(&loggerTime); + std::string preamble; + if(addCrToPreamble) { + preamble += "\r"; + } + preamble += logMessage + ": | " + zero_padded(loggerTime.hour, 2) + + ":" + zero_padded(loggerTime.minute, 2) + ":" + + zero_padded(loggerTime.second, 2) + "." + + zero_padded(loggerTime.usecond/1000, 3) + " | "; + return preamble; } -void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { - char array[BUF_SIZE]; - uint32_t length = end - begin; - if (length > sizeof(array)) { - length = sizeof(array); - } - memcpy(array, begin, length); - - for(; begin != end; begin++){ - printChar(begin); - } - -} -#endif #ifdef UT699 diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index a2bc4f4b1..74facafe0 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -3,43 +3,64 @@ #include #include -#include #include #ifndef UT699 + +/** + * @brief This is the underlying stream buffer which implements the + * streambuf class and overloads the overflow() and sync() methods + * @details + * This class is used to modify the output of the stream, for example by adding. + * It also calls the char printing function which is implemented in the + * board supply package (BSP). + */ class ServiceInterfaceBuffer: - public std::basic_streambuf> { + public std::streambuf { friend class ServiceInterfaceStream; public: - ServiceInterfaceBuffer(std::string set_message, uint16_t port, - bool addCrToPreamble); + ServiceInterfaceBuffer(std::string setMessage, bool errStream, + bool addCrToPreamble, uint16_t port); + protected: bool isActive; - // This is called when buffer becomes full. If - // buffer is not used, then this is called every - // time when characters are put to stream. + //! This is called when buffer becomes full. If + //! buffer is not used, then this is called every + //! time when characters are put to stream. int overflow(int c = Traits::eof()) override; - // This function is called when stream is flushed, - // for example when std::endl is put to stream. + //! This function is called when stream is flushed, + //! for example when std::endl is put to stream. int sync(void) override; private: - // For additional message information - std::string log_message; + //! For additional message information + std::string logMessage; // For EOF detection typedef std::char_traits Traits; - // This is useful for some terminal programs which do not have - // implicit carriage return with newline characters. + //! This is useful for some terminal programs which do not have + //! implicit carriage return with newline characters. bool addCrToPreamble; + //! This specifies to print to stderr and work in unbuffered mode. + bool errStream; // Work in buffer mode. It is also possible to work without buffer. static size_t const BUF_SIZE = 128; char buf[BUF_SIZE]; - // In this function, the characters are parsed. + //! In this function, the characters are parsed. void putChars(char const* begin, char const* end); + std::string getPreamble(); + + /** + * This helper function returns the zero padded string version of a number. + * The type is deduced automatically. + * @tparam T + * @param num + * @param width + * @return + */ template std::string zero_padded(const T& num, uint8_t width) { std::ostringstream string_to_pad; @@ -52,6 +73,7 @@ private: return result; } }; + #endif diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp index 40f52f1fe..783715484 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/serviceinterface/ServiceInterfaceStream.cpp @@ -1,11 +1,15 @@ #include +ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage, + bool errStream, bool addCrToPreamble, uint16_t port) : + std::ostream(&buf), + buf(setMessage, errStream, addCrToPreamble, port) { +} + void ServiceInterfaceStream::setActive( bool myActive) { this->buf.isActive = myActive; } -ServiceInterfaceStream::ServiceInterfaceStream(std::string set_message, - bool addCrToPreamble, uint16_t port) : - std::basic_ostream>(&buf), - buf(set_message, port, addCrToPreamble) { +std::string ServiceInterfaceStream::getPreamble() { + return buf.getPreamble(); } diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h index a445dcedd..aecd45c37 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/serviceinterface/ServiceInterfaceStream.h @@ -3,11 +3,9 @@ #include #include -#include -#include #include -// Unfortunately, there must be a forward declaration of log_fe +// Unfortunately, there must be a forward declaration of the log front end // (MUST be defined in main), to let the system know where to write to. namespace sif { extern std::ostream debug; @@ -18,14 +16,41 @@ extern std::ostream error; class ServiceInterfaceStream : - public std::basic_ostream> { + public std::ostream { protected: ServiceInterfaceBuffer buf; public: - ServiceInterfaceStream( std::string set_message, - bool addCrToPreamble = false, uint16_t port = 1234); + /** + * This constructor is used by specifying the preamble message. + * Optionally, the output can be directed to stderr and a CR character + * can be prepended to the preamble. + * @param set_message + * @param errStream + * @param addCrToPreamble + * @param port + */ + ServiceInterfaceStream(std::string setMessage, + bool errStream = false, bool addCrToPreamble = false, + uint16_t port = 1234); + + //! An inactive stream will not print anything. void setActive( bool ); + + /** + * This can be used to retrieve the preamble in case it should be printed in + * the unbuffered mode. + * @return Preamle consisting of log message and timestamp. + */ + std::string getPreamble(); }; +// Forward declaration of interface streams. These are needed so the public +// functions can be used by including this header +namespace sif { +extern ServiceInterfaceStream debugStream; +extern ServiceInterfaceStream infoStream; +extern ServiceInterfaceStream warningStream; +extern ServiceInterfaceStream errorStream; +} #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */