From 493322859a7b74e7566c185c4964efc6056300f8 Mon Sep 17 00:00:00 2001 From: Dakota Lazenby Date: Fri, 19 Feb 2021 08:51:15 -0500 Subject: [PATCH 1/8] * Edit project files -> ignore Visual Studio created folders & put lib file in dev project outputs --- .gitignore | 2 ++ CMakeLists.txt | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 290417d..de5f236 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *~ build *.user +.vs/ +out/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 306a724..a81467e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ link_directories( add_definitions(${PCL_DEFINITIONS}) - + set(client_SRCS src/modules/polar_to_cart_converter.cpp src/modules/distance_filter.cpp @@ -140,7 +140,8 @@ if (PACKAGE_FOR_DEV) if(WIN32) install(TARGETS quanergy_client EXPORT QuanergyClientTargets - RUNTIME DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib) + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT shlib) else() install(TARGETS quanergy_client EXPORT QuanergyClientTargets From 182c2c8a40fc94fff0e009507cf9bcda60fdca07 Mon Sep 17 00:00:00 2001 From: Dakota Lazenby Date: Fri, 19 Feb 2021 08:56:22 -0500 Subject: [PATCH 2/8] * Created minimally invasive alternative to passing messages on std::cout & std::cerr where users can consume messages --- CMakeLists.txt | 1 + apps/dynamic_connection.cpp | 15 +++ apps/visualizer.cpp | 53 ++++++++++ include/quanergy/client/exceptions.h | 20 +++- include/quanergy/client/impl/tcp_client.hpp | 31 +++--- include/quanergy/client/packet_header.h | 7 +- include/quanergy/common/notifications.h | 85 ++++++++++++++++ include/quanergy/parsers/data_packet_01.h | 5 +- include/quanergy/pipelines/async.h | 4 +- src/client/device_info.cpp | 7 +- src/common/notifications.cpp | 105 ++++++++++++++++++++ src/modules/encoder_angle_calibration.cpp | 12 ++- src/modules/ring_intensity_filter.cpp | 10 +- src/parsers/data_packet_parser_m_series.cpp | 8 +- src/pipelines/sensor_pipeline.cpp | 14 +-- 15 files changed, 333 insertions(+), 44 deletions(-) create mode 100644 include/quanergy/common/notifications.h create mode 100644 src/common/notifications.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a81467e..ea91b98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ add_definitions(${PCL_DEFINITIONS}) set(client_SRCS + src/common/notifications.cpp src/modules/polar_to_cart_converter.cpp src/modules/distance_filter.cpp src/modules/ring_intensity_filter.cpp diff --git a/apps/dynamic_connection.cpp b/apps/dynamic_connection.cpp index 4ec3835..2391d39 100644 --- a/apps/dynamic_connection.cpp +++ b/apps/dynamic_connection.cpp @@ -18,10 +18,25 @@ // sensor pipeline #include +// handle notifications +#include + int main(int argc, char** argv) { namespace po = boost::program_options; + // Pipe the notifications out to std::cout / std::cerr + quanergy::qout.connect([](const quanergy::NotificationType& type, const std::string& msg) + { + std::cout << msg; + }); + + // Pipe the notifications out to std::cout / std::cerr + quanergy::qerr.connect([](const quanergy::NotificationType& type, const std::string& msg) + { + std::cerr << msg; + }); + po::options_description description("Quanergy Client Dynamic Connection"); const po::positional_options_description p; // empty positional options diff --git a/apps/visualizer.cpp b/apps/visualizer.cpp index 77db584..99a622a 100644 --- a/apps/visualizer.cpp +++ b/apps/visualizer.cpp @@ -17,10 +17,28 @@ // sensor pipeline #include +// handle notifications +#include + +// TEST +#include + int main(int argc, char** argv) { namespace po = boost::program_options; + // Pipe the notifications out to std::cout / std::cerr + quanergy::qout.connect([](const quanergy::NotificationType& type, const std::string& msg) + { + std::cout << msg; + }); + + // Pipe the notifications out to std::cout / std::cerr + quanergy::qerr.connect([](const quanergy::NotificationType& type, const std::string& msg) + { + std::cerr << msg; + }); + po::options_description description("Quanergy Client Visualizer"); const po::positional_options_description p; // empty positional options @@ -137,11 +155,46 @@ int main(int argc, char** argv) std::unique_ptr pipeline; std::unique_ptr visualizer; + std::unique_ptr device_config; + try { // create client to get raw packets from the sensor client.reset(new quanergy::client::SensorClient(pipeline_settings.host, port, 100)); + /* + DEVICE CONFIG TEST + */ + + // create a device configurator + device_config.reset(new quanergy::client::DeviceConfig(pipeline_settings.host)); + + // Get the initial parameters from when the sensor connected + auto init_params = device_config->get_parameters(); + std::string ntp_ip_before = *(init_params->get_ntp_ip_addr()); + std::string ip_before = *(init_params->get_ipAddress()); + + bool success = true; + // Write new ntp_ip 5 times, check that it is written + for (int i = 100; i < 105; i++) + { + std::string new_ip = "192.168.1." + std::to_string(i); + success &= device_config->send_set_request( + device_config->new_set_request() + .set_ntp_ip_addr(new_ip)); + auto after_params = device_config->get_parameters(); + success &= (new_ip == *(after_params->get_ntp_ip_addr())); + } + + // Reset the parameters to factory stock + device_config->reset_parameters(); + auto reset_params = device_config->get_parameters(); + std::string ip = *(reset_params->get_ipAddress()); + + /* + END - DEVICE CONFIG TEST + */ + // create pipeline to produce point cloud from raw packets pipeline.reset(new quanergy::pipeline::SensorPipeline(pipeline_settings)); diff --git a/include/quanergy/client/exceptions.h b/include/quanergy/client/exceptions.h index f7de1f1..681cf58 100644 --- a/include/quanergy/client/exceptions.h +++ b/include/quanergy/client/exceptions.h @@ -35,15 +35,27 @@ namespace quanergy }; /** \brief error parsing header */ - struct InvalidHeaderError : public std::exception + struct ParseTimeoutError : public std::exception { - virtual const char* what() const throw() { return "Invalid header"; } + virtual const char* what() const throw() { return "Parse timeout error"; } + }; + + /** \brief error parsing header */ + struct InvalidHeaderError : public std::runtime_error + { + explicit InvalidHeaderError(const std::string& message) + : std::runtime_error("Invalid header! Details: " + message) {} + explicit InvalidHeaderError() + : std::runtime_error("Invalid header!") {} }; /** \brief packet size doesn't match data description */ - struct SizeMismatchError : public std::exception + struct SizeMismatchError : public std::runtime_error { - virtual const char* what() const throw() { return "Packet sizes don't match"; } + explicit SizeMismatchError(const std::string& message) + : std::runtime_error("Packet sizes don't match! Details: " + message) {} + explicit SizeMismatchError() + : std::runtime_error("Packet sizes don't match!") {} }; /** \brief Invalid packet */ diff --git a/include/quanergy/client/impl/tcp_client.hpp b/include/quanergy/client/impl/tcp_client.hpp index 223a21e..a6f0881 100755 --- a/include/quanergy/client/impl/tcp_client.hpp +++ b/include/quanergy/client/impl/tcp_client.hpp @@ -115,8 +115,8 @@ namespace quanergy template void TCPClient
::startDataConnect() { - std::cout << "Attempting to connect (" << host_query_.host_name() - << ":" << host_query_.service_name() << ")..." << std::endl; + qout << "Attempting to connect (" << host_query_.host_name() + << ":" << host_query_.service_name() << ")..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service_); try @@ -138,23 +138,25 @@ namespace quanergy } else if (error) { - std::cerr << "Unable to bind to socket (" << host_query_.host_name() - << ":" << host_query_.service_name() << ")! " - << error.message() << std::endl; + qerr << "Unable to bind to socket (" << host_query_.host_name() + << ":" << host_query_.service_name() << ")! " + << error.message() << std::endl; + throw SocketBindError(error.message()); } else { - std::cout << "Connection established" << std::endl; + qerr << "Connection established" << std::endl; + startDataRead(); } }); } catch (boost::system::system_error& e) { - std::cerr << "Unable to resolve host (" << host_query_.host_name() - << ":" << host_query_.service_name() << ")! " - << e.what() << std::endl; + qerr << "Unable to resolve host (" << host_query_.host_name() + << ":" << host_query_.service_name() << ")! " + << e.what() << std::endl; throw SocketBindError(e.what()); } } @@ -177,8 +179,8 @@ namespace quanergy } else if (error) { - std::cerr << "Error reading header: " - << error.message() << std::endl; + qerr << "Error reading header: " + << error.message() << std::endl; throw SocketReadError(error.message()); } else @@ -213,8 +215,9 @@ namespace quanergy } else if (error) { - std::cerr << "Error reading body: " - << error.message() << std::endl; + qerr << "Error reading body: " + << error.message() << std::endl; + throw SocketReadError(error.message()); } else @@ -227,7 +230,7 @@ namespace quanergy while (buff_queue_.size() > max_queue_size_) { buff_queue_.pop(); - std::cout << "Warning: Client dropped packet due to full buffer" << std::endl; + qout << "Warning: Client dropped packet due to full buffer" << std::endl; } lk.unlock(); diff --git a/include/quanergy/client/packet_header.h b/include/quanergy/client/packet_header.h index 12d9abe..2fa719c 100644 --- a/include/quanergy/client/packet_header.h +++ b/include/quanergy/client/packet_header.h @@ -24,6 +24,8 @@ #include +#include + #include namespace quanergy @@ -98,9 +100,8 @@ namespace quanergy { if (deserialize(object.signature) != SIGNATURE) { - std::cerr << "Invalid header signature: " << std::hex << std::showbase - << object.signature << std::dec << std::noshowbase << std::endl; - + qerr << "Invalid header signature: " << std::hex << std::showbase + << object.signature << std::dec << std::noshowbase << std::endl; return false; } diff --git a/include/quanergy/common/notifications.h b/include/quanergy/common/notifications.h new file mode 100644 index 0000000..f0a77ec --- /dev/null +++ b/include/quanergy/common/notifications.h @@ -0,0 +1,85 @@ +/**************************************************************** + ** ** + ** Copyright(C) 2020 Quanergy Systems. All Rights Reserved. ** + ** Contact: http://www.quanergy.com ** + ** ** + ****************************************************************/ + + /** \file notifications.h + * \brief Define classes for handling notifications. + * + */ + +#ifndef QUANERGY_NOTIFICATIONS_H +#define QUANERGY_NOTIFICATIONS_H + +#include +#include + +// signals for output +#include + +#include + +namespace quanergy +{ + /** \brief severity level of the notification */ + enum class NotificationType { Trace, Debug, Info, Warning, Error, Critical }; + + /// Notifications (error messages) are output on a different signal + typedef boost::signals2::signal NotificationSignal; + + class DLLEXPORT INotify + { + public: + /** \brief Connect a slot to the signal which will be for outputting messages and notifications */ + boost::signals2::connection connect(const typename NotificationSignal::slot_type& subscriber); + + protected: + NotificationSignal notification_signal_; + }; + + class DLLEXPORT InfoBuf : public std::stringbuf, public INotify + { + public: + InfoBuf() = default; + virtual int sync() override; + }; + + class DLLEXPORT ErrorBuf : public std::stringbuf, public INotify + { + public: + ErrorBuf() = default; + virtual int sync() override; + }; + + class DLLEXPORT InfoStream : public std::ostream + { + public: + InfoStream(); + + /** \brief Connect a slot to the signal which will be for outputting messages and notifications */ + static boost::signals2::connection connect(const typename NotificationSignal::slot_type& subscriber); + + protected: + static InfoBuf buf; + }; + + class DLLEXPORT ErrorStream : public std::ostream + { + public: + ErrorStream(); + + /** \brief Connect a slot to the signal which will be for outputting messages and notifications */ + static boost::signals2::connection connect(const typename NotificationSignal::slot_type& subscriber); + + protected: + static ErrorBuf buf; + }; + + static InfoStream qout; + static ErrorStream qerr; + +} // namespace quanergy + +#endif \ No newline at end of file diff --git a/include/quanergy/parsers/data_packet_01.h b/include/quanergy/parsers/data_packet_01.h index ff2a6b0..4cf10d8 100644 --- a/include/quanergy/parsers/data_packet_01.h +++ b/include/quanergy/parsers/data_packet_01.h @@ -91,9 +91,10 @@ namespace quanergy sizeof(DataHeader01) + object.data_header.point_count * sizeof(DataPoint01)) { - std::cerr << "Invalid sizes: " << object.data_header.point_count + std::stringstream ss; + ss << "Invalid sizes: " << object.data_header.point_count << " points and " << object.packet_header.size << " bytes" << std::endl; - throw SizeMismatchError(); + throw SizeMismatchError(ss.str()); } object.data_points.resize(object.data_header.point_count); diff --git a/include/quanergy/pipelines/async.h b/include/quanergy/pipelines/async.h index 5e09cad..7e57c3a 100644 --- a/include/quanergy/pipelines/async.h +++ b/include/quanergy/pipelines/async.h @@ -22,6 +22,8 @@ #include #include +#include + namespace quanergy { namespace pipeline @@ -88,7 +90,7 @@ namespace quanergy // while shouldn't be necessary but doesn't hurt just to be sure while (input_queue_.size() > max_queue_size_) { - std::cerr << "Warning: AsyncModule dropped input due to full buffer" << std::endl; + qerr << "Warning: AsyncModule dropped input due to full buffer" << std::endl; input_queue_.pop(); } diff --git a/src/client/device_info.cpp b/src/client/device_info.cpp index a2407d9..703d039 100644 --- a/src/client/device_info.cpp +++ b/src/client/device_info.cpp @@ -17,6 +17,9 @@ #include #include +// Handle notifications +#include + using namespace quanergy::client; DeviceInfo::DeviceInfo(const std::string& host) @@ -25,7 +28,7 @@ DeviceInfo::DeviceInfo(const std::string& host) std::stringstream device_info_stream; // get deviceInfo from sensor for calibration - std::cout << "Attempting to get device info from " << host << std::endl; + quanergy::qout << "Attempting to get device info from " << host << std::endl; http_client.read(device_info_path_, device_info_stream); boost::property_tree::ptree device_info_tree; boost::property_tree::read_xml(device_info_stream, device_info_tree); @@ -63,7 +66,7 @@ DeviceInfo::DeviceInfo(const std::string& host) } // if laser data } // if cal data - + quanergy::qout << "... complete." << std::endl; } // constructor diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp new file mode 100644 index 0000000..1af27c5 --- /dev/null +++ b/src/common/notifications.cpp @@ -0,0 +1,105 @@ +/**************************************************************** + ** ** + ** Copyright(C) 2020 Quanergy Systems. All Rights Reserved. ** + ** Contact: http://www.quanergy.com ** + ** ** + ****************************************************************/ + +#include + +using namespace quanergy; + +boost::signals2::connection INotify::connect(const typename NotificationSignal::slot_type& subscriber) +{ + return notification_signal_.connect(subscriber); +} + +// Try to find a NotificationType in the message, if one is not found, the input type is not changed +bool FindNotificationTag(const std::string& str, NotificationType& type) +{ + if (str.find("[trace]") != std::string::npos || + str.find("[Trace]") != std::string::npos || + str.find("[TRACE]") != std::string::npos) + { + type = NotificationType::Trace; + } + else if (str.find("[debug]") != std::string::npos || + str.find("[Debug]") != std::string::npos || + str.find("[DEBUG]") != std::string::npos) + { + type = NotificationType::Debug; + } + else if (str.find("[info]") != std::string::npos || + str.find("[Info]") != std::string::npos || + str.find("[INFO]") != std::string::npos) + { + type = NotificationType::Info; + } + else if (str.find("[warn]") != std::string::npos || + str.find("[warning]") != std::string::npos || + str.find("[Warn]") != std::string::npos || + str.find("[Warning]") != std::string::npos || + str.find("[WARN]") != std::string::npos || + str.find("[WARNING]") != std::string::npos) + { + type = NotificationType::Warning; + } + else if (str.find("[error]") != std::string::npos || + str.find("[Error]") != std::string::npos || + str.find("[ERROR]") != std::string::npos) + { + type = NotificationType::Error; + } + else if (str.find("[critical]") != std::string::npos || + str.find("[Critical]") != std::string::npos || + str.find("[CRITICAL]") != std::string::npos) + { + type = NotificationType::Critical; + } + else + { + return false; + } + + return true; +} + +int InfoBuf::sync() +{ + NotificationType type = NotificationType::Info; + FindNotificationTag(this->str(), type); + // do something with this->str() here + notification_signal_(type, this->str()); + // (optionally clear buffer afterwards) + this->str(""); + return 0; +} + +int ErrorBuf::sync() +{ + NotificationType type = NotificationType::Error; + FindNotificationTag(this->str(), type); + // do something with this->str() here + notification_signal_(type, this->str()); + // (optionally clear buffer afterwards) + this->str(""); + return 0; +} + +InfoBuf InfoStream::buf; +InfoStream::InfoStream() : std::ostream(&buf) +{} + +boost::signals2::connection InfoStream::connect(const typename NotificationSignal::slot_type& subscriber) +{ + return buf.connect(subscriber); +} + +ErrorBuf ErrorStream::buf; +ErrorStream::ErrorStream() : std::ostream(&buf) +{} + +boost::signals2::connection ErrorStream::connect(const typename NotificationSignal::slot_type& subscriber) +{ + return buf.connect(subscriber); +} diff --git a/src/modules/encoder_angle_calibration.cpp b/src/modules/encoder_angle_calibration.cpp index c397649..4fee97d 100644 --- a/src/modules/encoder_angle_calibration.cpp +++ b/src/modules/encoder_angle_calibration.cpp @@ -14,6 +14,8 @@ #include +#include + #include namespace quanergy @@ -118,7 +120,7 @@ namespace quanergy { if (!started_calibration_) { - std::cout << "QuanergyClient: Starting encoder calibration. This may take up to " + qout << "QuanergyClient: Starting encoder calibration. This may take up to " << std::chrono::duration_cast(timeout_).count() << " seconds to complete..." << std::endl; started_calibration_ = true; @@ -143,7 +145,7 @@ namespace quanergy std::stringstream msg; msg << "QuanergyClient: Encoder calibration not required for this sensor.\n" "Average amplitude calculated: " << ba::mean(amplitude_accumulator_); - std::cout << msg.str() << std::endl; + qout << msg.str() << std::endl; calibration_complete_ = true; amplitude_ = 0.; @@ -275,7 +277,7 @@ namespace quanergy { if (first_run_) { - std::cout << "QuanergyClient: AMPLITUDE(rads), PHASE(rads)" << std::endl; + qout << "QuanergyClient: AMPLITUDE(rads), PHASE(rads)" << std::endl; first_run_ = false; } @@ -283,7 +285,7 @@ namespace quanergy output << sine_parameters.first << "," << sine_parameters.second << std::endl; - std::cout << output.str(); + qout << output.str(); continue; } @@ -321,7 +323,7 @@ namespace quanergy amplitude_ = ba::mean(amplitude_accumulator_); phase_ = phase_averager_.avg(); - std::cout << "QuanergyClient: Calibration complete." << std::endl + qout << "QuanergyClient: Calibration complete." << std::endl << " amplitude : " << amplitude_ << std::endl << " phase : " << phase_ << std::endl; diff --git a/src/modules/ring_intensity_filter.cpp b/src/modules/ring_intensity_filter.cpp index 7d54d89..924bf40 100644 --- a/src/modules/ring_intensity_filter.cpp +++ b/src/modules/ring_intensity_filter.cpp @@ -7,6 +7,8 @@ #include +#include + namespace quanergy { namespace client @@ -97,7 +99,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - std::cerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; + qerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; return std::numeric_limits::quiet_NaN(); } @@ -110,7 +112,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - std::cerr << "Index out of bound! Beam index should be between 0 and " + qerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; } else @@ -124,7 +126,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - std::cerr << "Index out of bound! Beam index should be between 0 and " + qerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; return -1; } @@ -138,7 +140,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - std::cerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; + qerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; } else { diff --git a/src/parsers/data_packet_parser_m_series.cpp b/src/parsers/data_packet_parser_m_series.cpp index 1d0b948..aac50b2 100644 --- a/src/parsers/data_packet_parser_m_series.cpp +++ b/src/parsers/data_packet_parser_m_series.cpp @@ -7,6 +7,8 @@ #include +#include + namespace quanergy { namespace client @@ -123,7 +125,7 @@ namespace quanergy if (status != previous_status_) { - std::cerr << "Sensor status: " << std::uint16_t(status) << std::endl; + qerr << "Sensor status: " << std::uint16_t(status) << std::endl; previous_status_ = status; } @@ -191,7 +193,7 @@ namespace quanergy if(cloudfull) { - std::cout << "Warning: Maximum cloud size limit of (" + qout << "Warning: Maximum cloud size limit of (" << maximum_cloud_size_ << ") exceeded" << std::endl; } @@ -217,7 +219,7 @@ namespace quanergy } else if(current_cloud_->size() > 0) { - std::cout << "Warning: Minimum cloud size limit of (" << minimum_cloud_size_ + qout << "Warning: Minimum cloud size limit of (" << minimum_cloud_size_ << ") not reached (" << current_cloud_->size() << ")" << std::endl; } diff --git a/src/pipelines/sensor_pipeline.cpp b/src/pipelines/sensor_pipeline.cpp index 094e933..5283281 100644 --- a/src/pipelines/sensor_pipeline.cpp +++ b/src/pipelines/sensor_pipeline.cpp @@ -10,6 +10,8 @@ #include #include +#include + namespace quanergy { namespace pipeline @@ -21,7 +23,7 @@ namespace quanergy // get sensor type auto model = device_info.model(); - std::cout << "got model from device info: " << model << std::endl; + qout << "got model from device info: " << model << std::endl; // 'model.rfind(sub, 0) == 0' checks only the first position (the beginning) of model for sub // and is true if sub was found there @@ -34,22 +36,22 @@ namespace quanergy // encoder params if (settings.calibrate) { - std::cout << "Encoder calibration will be performed" << std::endl; + qout << "Encoder calibration will be performed" << std::endl; encoder_corrector.setFrameRate(settings.frame_rate); } else if (settings.override_encoder_params) { - std::cout << "Encoder calibration parameters provided will be applied" << std::endl; + qout << "Encoder calibration parameters provided will be applied" << std::endl; encoder_corrector.setParams(settings.amplitude, settings.phase); } else if (device_info.amplitude() && device_info.phase()) { - std::cout << "Encoder calibration parameters from the sensor will be applied" << std::endl; + qout << "Encoder calibration parameters from the sensor will be applied" << std::endl; encoder_corrector.setParams(*device_info.amplitude(), *device_info.phase()); } else { - std::cout << "No encoder calibration will be applied" << std::endl; + qout << "No encoder calibration will be applied" << std::endl; encoder_corrector.setParams(0.f, 0.f); // turns off calibration procedure } @@ -67,7 +69,7 @@ namespace quanergy } else if (model.rfind("M8", 0) == 0) { - std::cout << "No vertical angle calibration information available on sensor, proceeding with M8 defaults" << std::endl; + qout << "No vertical angle calibration information available on sensor, proceeding with M8 defaults" << std::endl; // tell parsers to use M8 defaults parser.get().setVerticalAngles(quanergy::client::SensorType::M8); From 0ad1504ac40ce1780a796fdcd39c24415c82b96c Mon Sep 17 00:00:00 2001 From: Ross Taylor Date: Mon, 17 May 2021 15:51:11 -0500 Subject: [PATCH 3/8] rm: device config (temporary) will revert this before moving onto device config integration --- apps/visualizer.cpp | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/apps/visualizer.cpp b/apps/visualizer.cpp index 99a622a..3597370 100644 --- a/apps/visualizer.cpp +++ b/apps/visualizer.cpp @@ -20,9 +20,6 @@ // handle notifications #include -// TEST -#include - int main(int argc, char** argv) { namespace po = boost::program_options; @@ -155,46 +152,11 @@ int main(int argc, char** argv) std::unique_ptr pipeline; std::unique_ptr visualizer; - std::unique_ptr device_config; - try { // create client to get raw packets from the sensor client.reset(new quanergy::client::SensorClient(pipeline_settings.host, port, 100)); - /* - DEVICE CONFIG TEST - */ - - // create a device configurator - device_config.reset(new quanergy::client::DeviceConfig(pipeline_settings.host)); - - // Get the initial parameters from when the sensor connected - auto init_params = device_config->get_parameters(); - std::string ntp_ip_before = *(init_params->get_ntp_ip_addr()); - std::string ip_before = *(init_params->get_ipAddress()); - - bool success = true; - // Write new ntp_ip 5 times, check that it is written - for (int i = 100; i < 105; i++) - { - std::string new_ip = "192.168.1." + std::to_string(i); - success &= device_config->send_set_request( - device_config->new_set_request() - .set_ntp_ip_addr(new_ip)); - auto after_params = device_config->get_parameters(); - success &= (new_ip == *(after_params->get_ntp_ip_addr())); - } - - // Reset the parameters to factory stock - device_config->reset_parameters(); - auto reset_params = device_config->get_parameters(); - std::string ip = *(reset_params->get_ipAddress()); - - /* - END - DEVICE CONFIG TEST - */ - // create pipeline to produce point cloud from raw packets pipeline.reset(new quanergy::pipeline::SensorPipeline(pipeline_settings)); From 7c7e4ca0f464d75b02825f5e740f744139737cee Mon Sep 17 00:00:00 2001 From: Ross Taylor Date: Tue, 18 May 2021 16:43:59 -0500 Subject: [PATCH 4/8] Update: using an ostream sink model for output with defaults --- apps/dynamic_connection.cpp | 12 -- apps/visualizer.cpp | 12 -- include/quanergy/client/impl/tcp_client.hpp | 14 +-- include/quanergy/client/packet_header.h | 2 +- include/quanergy/common/notifications.h | 124 ++++++++++---------- include/quanergy/pipelines/async.h | 2 +- src/client/device_info.cpp | 4 +- src/common/notifications.cpp | 121 +++++++------------ src/modules/encoder_angle_calibration.cpp | 10 +- src/modules/ring_intensity_filter.cpp | 8 +- src/parsers/data_packet_parser_m_series.cpp | 6 +- src/pipelines/sensor_pipeline.cpp | 12 +- 12 files changed, 138 insertions(+), 189 deletions(-) diff --git a/apps/dynamic_connection.cpp b/apps/dynamic_connection.cpp index 2391d39..8113945 100644 --- a/apps/dynamic_connection.cpp +++ b/apps/dynamic_connection.cpp @@ -25,18 +25,6 @@ int main(int argc, char** argv) { namespace po = boost::program_options; - // Pipe the notifications out to std::cout / std::cerr - quanergy::qout.connect([](const quanergy::NotificationType& type, const std::string& msg) - { - std::cout << msg; - }); - - // Pipe the notifications out to std::cout / std::cerr - quanergy::qerr.connect([](const quanergy::NotificationType& type, const std::string& msg) - { - std::cerr << msg; - }); - po::options_description description("Quanergy Client Dynamic Connection"); const po::positional_options_description p; // empty positional options diff --git a/apps/visualizer.cpp b/apps/visualizer.cpp index 3597370..ba134ed 100644 --- a/apps/visualizer.cpp +++ b/apps/visualizer.cpp @@ -24,18 +24,6 @@ int main(int argc, char** argv) { namespace po = boost::program_options; - // Pipe the notifications out to std::cout / std::cerr - quanergy::qout.connect([](const quanergy::NotificationType& type, const std::string& msg) - { - std::cout << msg; - }); - - // Pipe the notifications out to std::cout / std::cerr - quanergy::qerr.connect([](const quanergy::NotificationType& type, const std::string& msg) - { - std::cerr << msg; - }); - po::options_description description("Quanergy Client Visualizer"); const po::positional_options_description p; // empty positional options diff --git a/include/quanergy/client/impl/tcp_client.hpp b/include/quanergy/client/impl/tcp_client.hpp index a6f0881..774caa5 100755 --- a/include/quanergy/client/impl/tcp_client.hpp +++ b/include/quanergy/client/impl/tcp_client.hpp @@ -115,7 +115,7 @@ namespace quanergy template void TCPClient
::startDataConnect() { - qout << "Attempting to connect (" << host_query_.host_name() + log.info << "Attempting to connect (" << host_query_.host_name() << ":" << host_query_.service_name() << ")..." << std::endl; boost::asio::ip::tcp::resolver resolver(io_service_); @@ -138,7 +138,7 @@ namespace quanergy } else if (error) { - qerr << "Unable to bind to socket (" << host_query_.host_name() + log.error << "Unable to bind to socket (" << host_query_.host_name() << ":" << host_query_.service_name() << ")! " << error.message() << std::endl; @@ -146,7 +146,7 @@ namespace quanergy } else { - qerr << "Connection established" << std::endl; + log.info << "Connection established" << std::endl; startDataRead(); } @@ -154,7 +154,7 @@ namespace quanergy } catch (boost::system::system_error& e) { - qerr << "Unable to resolve host (" << host_query_.host_name() + log.error << "Unable to resolve host (" << host_query_.host_name() << ":" << host_query_.service_name() << ")! " << e.what() << std::endl; throw SocketBindError(e.what()); @@ -179,7 +179,7 @@ namespace quanergy } else if (error) { - qerr << "Error reading header: " + log.error << "Error reading header: " << error.message() << std::endl; throw SocketReadError(error.message()); } @@ -215,7 +215,7 @@ namespace quanergy } else if (error) { - qerr << "Error reading body: " + log.error << "Error reading body: " << error.message() << std::endl; throw SocketReadError(error.message()); @@ -230,7 +230,7 @@ namespace quanergy while (buff_queue_.size() > max_queue_size_) { buff_queue_.pop(); - qout << "Warning: Client dropped packet due to full buffer" << std::endl; + log.warn << "Warning: Client dropped packet due to full buffer" << std::endl; } lk.unlock(); diff --git a/include/quanergy/client/packet_header.h b/include/quanergy/client/packet_header.h index 2fa719c..6f6057e 100644 --- a/include/quanergy/client/packet_header.h +++ b/include/quanergy/client/packet_header.h @@ -100,7 +100,7 @@ namespace quanergy { if (deserialize(object.signature) != SIGNATURE) { - qerr << "Invalid header signature: " << std::hex << std::showbase + log.error << "Invalid header signature: " << std::hex << std::showbase << object.signature << std::dec << std::noshowbase << std::endl; return false; } diff --git a/include/quanergy/common/notifications.h b/include/quanergy/common/notifications.h index f0a77ec..24c39bf 100644 --- a/include/quanergy/common/notifications.h +++ b/include/quanergy/common/notifications.h @@ -16,69 +16,75 @@ #include #include -// signals for output -#include - #include namespace quanergy { - /** \brief severity level of the notification */ - enum class NotificationType { Trace, Debug, Info, Warning, Error, Critical }; - - /// Notifications (error messages) are output on a different signal - typedef boost::signals2::signal NotificationSignal; - - class DLLEXPORT INotify - { - public: - /** \brief Connect a slot to the signal which will be for outputting messages and notifications */ - boost::signals2::connection connect(const typename NotificationSignal::slot_type& subscriber); - - protected: - NotificationSignal notification_signal_; - }; - - class DLLEXPORT InfoBuf : public std::stringbuf, public INotify - { - public: - InfoBuf() = default; - virtual int sync() override; - }; - - class DLLEXPORT ErrorBuf : public std::stringbuf, public INotify - { - public: - ErrorBuf() = default; - virtual int sync() override; - }; - - class DLLEXPORT InfoStream : public std::ostream - { - public: - InfoStream(); - - /** \brief Connect a slot to the signal which will be for outputting messages and notifications */ - static boost::signals2::connection connect(const typename NotificationSignal::slot_type& subscriber); - - protected: - static InfoBuf buf; - }; - - class DLLEXPORT ErrorStream : public std::ostream - { - public: - ErrorStream(); - - /** \brief Connect a slot to the signal which will be for outputting messages and notifications */ - static boost::signals2::connection connect(const typename NotificationSignal::slot_type& subscriber); - - protected: - static ErrorBuf buf; - }; - - static InfoStream qout; - static ErrorStream qerr; + /** \brief severity level of the notification */ + enum class NotificationLevel { Trace, Debug, Info, Warn, Error }; + + /** \brief string buffer for notifier */ + class DLLEXPORT NotifierBuf : public std::stringbuf + { + public: + NotifierBuf() = default; + + /** \brief called on flush allowing us to forward to sink_ */ + virtual int sync() override; + + /** \brief set the downstream sink */ + void SetSink(std::ostream* sink) {sink_ = sink;} + + protected: + /** \brief sink to stream to on flush */ + std::ostream* sink_ = nullptr; + }; + + /** \brief ostream for notifier */ + class DLLEXPORT NotifierStream : public std::ostream + { + public: + NotifierStream() : std::ostream(&buf_) {} + + /** \brief set the downstream sink */ + void SetSink(std::ostream* sink) {buf_.SetSink(sink);} + + protected: + /** \brief the notification buffer for this stream */ + NotifierBuf buf_; + }; + + /** \brief class to keep the various streams + * by default, error streams to cerr and info and warn stream to cout + */ + class DLLEXPORT Notifier + { + public: + Notifier(); + + /** \brief set the downstream sink for one or more streams */ + void SetSinks(std::ostream* sink, NotificationLevel minLevel = NotificationLevel::Trace, NotificationLevel maxLevel = NotificationLevel::Error); + /** \brief set the downstream sink for one stream */ + void SetSink(std::ostream* sink, NotificationLevel level); + + /** \brief clear the downstream sink for one or more streams */ + void ClearSinks(NotificationLevel minLevel = NotificationLevel::Trace, NotificationLevel maxLevel = NotificationLevel::Error); + /** \brief clear the downstream sink for one stream */ + void ClearSink(NotificationLevel level); + + /** \brief the error stream */ + NotifierStream error; + /** \brief the warn stream */ + NotifierStream warn; + /** \brief the info stream */ + NotifierStream info; + /** \brief the debug stream */ + NotifierStream debug; + /** \brief the info stream */ + NotifierStream trace; + }; + + static Notifier log; } // namespace quanergy diff --git a/include/quanergy/pipelines/async.h b/include/quanergy/pipelines/async.h index 7e57c3a..0d942d6 100644 --- a/include/quanergy/pipelines/async.h +++ b/include/quanergy/pipelines/async.h @@ -90,7 +90,7 @@ namespace quanergy // while shouldn't be necessary but doesn't hurt just to be sure while (input_queue_.size() > max_queue_size_) { - qerr << "Warning: AsyncModule dropped input due to full buffer" << std::endl; + log.warn << "Warning: AsyncModule dropped input due to full buffer" << std::endl; input_queue_.pop(); } diff --git a/src/client/device_info.cpp b/src/client/device_info.cpp index 703d039..3842d03 100644 --- a/src/client/device_info.cpp +++ b/src/client/device_info.cpp @@ -28,7 +28,7 @@ DeviceInfo::DeviceInfo(const std::string& host) std::stringstream device_info_stream; // get deviceInfo from sensor for calibration - quanergy::qout << "Attempting to get device info from " << host << std::endl; + quanergy::log.info << "Attempting to get device info from " << host << std::endl; http_client.read(device_info_path_, device_info_stream); boost::property_tree::ptree device_info_tree; boost::property_tree::read_xml(device_info_stream, device_info_tree); @@ -66,7 +66,7 @@ DeviceInfo::DeviceInfo(const std::string& host) } // if laser data } // if cal data - quanergy::qout << "... complete." << std::endl; + quanergy::log.info << "... complete." << std::endl; } // constructor diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp index 1af27c5..da3dc3e 100644 --- a/src/common/notifications.cpp +++ b/src/common/notifications.cpp @@ -9,97 +9,64 @@ using namespace quanergy; -boost::signals2::connection INotify::connect(const typename NotificationSignal::slot_type& subscriber) +static inline bool checkLevel(NotificationLevel level, NotificationLevel min, NotificationLevel max) { - return notification_signal_.connect(subscriber); + return (level >= min && level <= max); } -// Try to find a NotificationType in the message, if one is not found, the input type is not changed -bool FindNotificationTag(const std::string& str, NotificationType& type) +int NotifierBuf::sync() { - if (str.find("[trace]") != std::string::npos || - str.find("[Trace]") != std::string::npos || - str.find("[TRACE]") != std::string::npos) - { - type = NotificationType::Trace; - } - else if (str.find("[debug]") != std::string::npos || - str.find("[Debug]") != std::string::npos || - str.find("[DEBUG]") != std::string::npos) - { - type = NotificationType::Debug; - } - else if (str.find("[info]") != std::string::npos || - str.find("[Info]") != std::string::npos || - str.find("[INFO]") != std::string::npos) - { - type = NotificationType::Info; - } - else if (str.find("[warn]") != std::string::npos || - str.find("[warning]") != std::string::npos || - str.find("[Warn]") != std::string::npos || - str.find("[Warning]") != std::string::npos || - str.find("[WARN]") != std::string::npos || - str.find("[WARNING]") != std::string::npos) - { - type = NotificationType::Warning; - } - else if (str.find("[error]") != std::string::npos || - str.find("[Error]") != std::string::npos || - str.find("[ERROR]") != std::string::npos) - { - type = NotificationType::Error; - } - else if (str.find("[critical]") != std::string::npos || - str.find("[Critical]") != std::string::npos || - str.find("[CRITICAL]") != std::string::npos) - { - type = NotificationType::Critical; - } - else - { - return false; - } - - return true; + // NotificationType type = NotificationType::Info; + // notification_signal_(type, this->str()); + if (sink_ && !this->str().empty()) + (*sink_) << this->str(); + + this->str(""); + return 0; } -int InfoBuf::sync() +Notifier::Notifier() { - NotificationType type = NotificationType::Info; - FindNotificationTag(this->str(), type); - // do something with this->str() here - notification_signal_(type, this->str()); - // (optionally clear buffer afterwards) - this->str(""); - return 0; + // default to Info & Warn on cout and Error on cerr + SetSinks(&std::cout, NotificationLevel::Info, NotificationLevel::Warn); + SetSink(&std::cerr, NotificationLevel::Error); } -int ErrorBuf::sync() +void Notifier::SetSinks(std::ostream* sink, NotificationLevel minLevel, NotificationLevel maxLevel) { - NotificationType type = NotificationType::Error; - FindNotificationTag(this->str(), type); - // do something with this->str() here - notification_signal_(type, this->str()); - // (optionally clear buffer afterwards) - this->str(""); - return 0; + if (checkLevel(NotificationLevel::Trace, minLevel, maxLevel)) + { + trace.SetSink(sink); + } + if (checkLevel(NotificationLevel::Debug, minLevel, maxLevel)) + { + debug.SetSink(sink); + } + if (checkLevel(NotificationLevel::Info, minLevel, maxLevel)) + { + info.SetSink(sink); + } + if (checkLevel(NotificationLevel::Warn, minLevel, maxLevel)) + { + warn.SetSink(sink); + } + if (checkLevel(NotificationLevel::Error, minLevel, maxLevel)) + { + error.SetSink(sink); + } } -InfoBuf InfoStream::buf; -InfoStream::InfoStream() : std::ostream(&buf) -{} - -boost::signals2::connection InfoStream::connect(const typename NotificationSignal::slot_type& subscriber) +void Notifier::SetSink(std::ostream* sink, NotificationLevel level) { - return buf.connect(subscriber); + SetSinks(sink, level, level); } -ErrorBuf ErrorStream::buf; -ErrorStream::ErrorStream() : std::ostream(&buf) -{} - -boost::signals2::connection ErrorStream::connect(const typename NotificationSignal::slot_type& subscriber) +void Notifier::ClearSinks(NotificationLevel minLevel, NotificationLevel maxLevel) { - return buf.connect(subscriber); + SetSinks(nullptr, minLevel, maxLevel); } + +void Notifier::ClearSink(NotificationLevel level) +{ + ClearSinks(level, level); +} \ No newline at end of file diff --git a/src/modules/encoder_angle_calibration.cpp b/src/modules/encoder_angle_calibration.cpp index b143add..b5631bb 100644 --- a/src/modules/encoder_angle_calibration.cpp +++ b/src/modules/encoder_angle_calibration.cpp @@ -119,7 +119,7 @@ namespace quanergy { if (!started_calibration_) { - qout << "QuanergyClient: Starting encoder calibration. This may take up to " + log.info << "QuanergyClient: Starting encoder calibration. This may take up to " << std::chrono::duration_cast(timeout_).count() << " seconds to complete..." << std::endl; started_calibration_ = true; @@ -142,7 +142,7 @@ namespace quanergy std::stringstream msg; msg << "QuanergyClient: Encoder calibration not required for this sensor.\n" "Average amplitude calculated: " << ba::mean(amplitude_accumulator_); - qout << msg.str() << std::endl; + log.info << msg.str() << std::endl; setParams(0., 0.); applyCalibration(cloud_ptr); @@ -280,7 +280,7 @@ namespace quanergy { if (first_run_) { - qout << "QuanergyClient: AMPLITUDE(rads), PHASE(rads)" << std::endl; + log.info << "QuanergyClient: AMPLITUDE(rads), PHASE(rads)" << std::endl; first_run_ = false; } @@ -288,7 +288,7 @@ namespace quanergy output << sine_parameters.first << "," << sine_parameters.second << std::endl; - qout << output.str(); + log.info << output.str(); continue; } @@ -325,7 +325,7 @@ namespace quanergy { setParams(ba::mean(amplitude_accumulator_), phase_averager_.avg()); - qout << "QuanergyClient: Calibration complete." << std::endl + log.info << "QuanergyClient: Calibration complete." << std::endl << " amplitude : " << amplitude_ << std::endl << " phase : " << phase_ << std::endl; diff --git a/src/modules/ring_intensity_filter.cpp b/src/modules/ring_intensity_filter.cpp index 924bf40..7316665 100644 --- a/src/modules/ring_intensity_filter.cpp +++ b/src/modules/ring_intensity_filter.cpp @@ -99,7 +99,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - qerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; + log.error << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; return std::numeric_limits::quiet_NaN(); } @@ -112,7 +112,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - qerr << "Index out of bound! Beam index should be between 0 and " + log.error << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; } else @@ -126,7 +126,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - qerr << "Index out of bound! Beam index should be between 0 and " + log.error << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; return -1; } @@ -140,7 +140,7 @@ namespace quanergy { if (laser_beam >= M_SERIES_NUM_LASERS) { - qerr << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; + log.error << "Index out of bound! Beam index should be between 0 and " << M_SERIES_NUM_LASERS << std::endl; } else { diff --git a/src/parsers/data_packet_parser_m_series.cpp b/src/parsers/data_packet_parser_m_series.cpp index aac50b2..6c10e7a 100644 --- a/src/parsers/data_packet_parser_m_series.cpp +++ b/src/parsers/data_packet_parser_m_series.cpp @@ -125,7 +125,7 @@ namespace quanergy if (status != previous_status_) { - qerr << "Sensor status: " << std::uint16_t(status) << std::endl; + log.error << "Sensor status: " << std::uint16_t(status) << std::endl; previous_status_ = status; } @@ -193,7 +193,7 @@ namespace quanergy if(cloudfull) { - qout << "Warning: Maximum cloud size limit of (" + log.warn << "Warning: Maximum cloud size limit of (" << maximum_cloud_size_ << ") exceeded" << std::endl; } @@ -219,7 +219,7 @@ namespace quanergy } else if(current_cloud_->size() > 0) { - qout << "Warning: Minimum cloud size limit of (" << minimum_cloud_size_ + log.warn << "Warning: Minimum cloud size limit of (" << minimum_cloud_size_ << ") not reached (" << current_cloud_->size() << ")" << std::endl; } diff --git a/src/pipelines/sensor_pipeline.cpp b/src/pipelines/sensor_pipeline.cpp index 5283281..4ee7489 100644 --- a/src/pipelines/sensor_pipeline.cpp +++ b/src/pipelines/sensor_pipeline.cpp @@ -23,7 +23,7 @@ namespace quanergy // get sensor type auto model = device_info.model(); - qout << "got model from device info: " << model << std::endl; + log.info << "got model from device info: " << model << std::endl; // 'model.rfind(sub, 0) == 0' checks only the first position (the beginning) of model for sub // and is true if sub was found there @@ -36,22 +36,22 @@ namespace quanergy // encoder params if (settings.calibrate) { - qout << "Encoder calibration will be performed" << std::endl; + log.info << "Encoder calibration will be performed" << std::endl; encoder_corrector.setFrameRate(settings.frame_rate); } else if (settings.override_encoder_params) { - qout << "Encoder calibration parameters provided will be applied" << std::endl; + log.info << "Encoder calibration parameters provided will be applied" << std::endl; encoder_corrector.setParams(settings.amplitude, settings.phase); } else if (device_info.amplitude() && device_info.phase()) { - qout << "Encoder calibration parameters from the sensor will be applied" << std::endl; + log.info << "Encoder calibration parameters from the sensor will be applied" << std::endl; encoder_corrector.setParams(*device_info.amplitude(), *device_info.phase()); } else { - qout << "No encoder calibration will be applied" << std::endl; + log.info << "No encoder calibration will be applied" << std::endl; encoder_corrector.setParams(0.f, 0.f); // turns off calibration procedure } @@ -69,7 +69,7 @@ namespace quanergy } else if (model.rfind("M8", 0) == 0) { - qout << "No vertical angle calibration information available on sensor, proceeding with M8 defaults" << std::endl; + log.warn << "No vertical angle calibration information available on sensor, proceeding with M8 defaults" << std::endl; // tell parsers to use M8 defaults parser.get().setVerticalAngles(quanergy::client::SensorType::M8); From a6cb06cb8dd656db8e7c1dae65713b47101e4188 Mon Sep 17 00:00:00 2001 From: Ross Taylor Date: Tue, 18 May 2021 18:49:31 -0500 Subject: [PATCH 5/8] Add: some logger functionality --- include/quanergy/common/notifications.h | 41 ++++++++++++-- src/common/notifications.cpp | 75 +++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 11 deletions(-) diff --git a/include/quanergy/common/notifications.h b/include/quanergy/common/notifications.h index 24c39bf..02bd0ec 100644 --- a/include/quanergy/common/notifications.h +++ b/include/quanergy/common/notifications.h @@ -27,27 +27,50 @@ namespace quanergy class DLLEXPORT NotifierBuf : public std::stringbuf { public: - NotifierBuf() = default; + /** \brief constructor + * \param name notifier name printed in output + * \param level notifier level printed in output + */ + NotifierBuf(std::string name, NotificationLevel level); /** \brief called on flush allowing us to forward to sink_ */ virtual int sync() override; /** \brief set the downstream sink */ - void SetSink(std::ostream* sink) {sink_ = sink;} + void SetSink(std::ostream* sink) { sink_ = sink; } + + /** \brief enable formatting on output (time, level, name) */ + void EnableFormatting(bool enable = true) { add_formatting_ = enable; } protected: /** \brief sink to stream to on flush */ std::ostream* sink_ = nullptr; + + /** \brief flag determining whether to include time, level, and name */ + bool add_formatting_ = true; + + /** \brief name used for formatting */ + std::string name_; + + /** \brief level string used for formatting */ + std::string level_string_; }; /** \brief ostream for notifier */ class DLLEXPORT NotifierStream : public std::ostream { public: - NotifierStream() : std::ostream(&buf_) {} + /** \brief constructor + * \param name notifier name printed in output + * \param level notifier level printed in output + */ + NotifierStream(std::string name, NotificationLevel level); /** \brief set the downstream sink */ - void SetSink(std::ostream* sink) {buf_.SetSink(sink);} + void SetSink(std::ostream* sink) { buf_.SetSink(sink); } + + /** \brief enable formatting on output (time, level, name) */ + void EnableFormatting(bool enable = true) { buf_.EnableFormatting(enable); } protected: /** \brief the notification buffer for this stream */ @@ -60,7 +83,10 @@ namespace quanergy class DLLEXPORT Notifier { public: - Notifier(); + /** \brief constructor + * \param name notifier name printed in output + */ + Notifier(std::string name); /** \brief set the downstream sink for one or more streams */ void SetSinks(std::ostream* sink, NotificationLevel minLevel = NotificationLevel::Trace, NotificationLevel maxLevel = NotificationLevel::Error); @@ -72,6 +98,9 @@ namespace quanergy /** \brief clear the downstream sink for one stream */ void ClearSink(NotificationLevel level); + /** \brief enable formatting on output (time, level, name) */ + void EnableFormatting(bool enable = true); + /** \brief the error stream */ NotifierStream error; /** \brief the warn stream */ @@ -84,7 +113,7 @@ namespace quanergy NotifierStream trace; }; - static Notifier log; + static Notifier log {"QuanergyClient"}; } // namespace quanergy diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp index da3dc3e..e619355 100644 --- a/src/common/notifications.cpp +++ b/src/common/notifications.cpp @@ -7,6 +7,9 @@ #include +#include +#include + using namespace quanergy; static inline bool checkLevel(NotificationLevel level, NotificationLevel min, NotificationLevel max) @@ -14,18 +17,71 @@ static inline bool checkLevel(NotificationLevel level, NotificationLevel min, No return (level >= min && level <= max); } +static std::string getTime() +{ + auto now = std::chrono::system_clock::now(); + auto itt = std::chrono::system_clock::to_time_t(now); + + std::stringstream ss; + ss << std::put_time(std::localtime(&itt), "%Y-%m-%d %H:%M:%S"); + return ss.str(); +} + +NotifierBuf::NotifierBuf(std::string name, NotificationLevel level) +: name_(name) +{ + switch (level) + { + case NotificationLevel::Trace: + level_string_ = "Trace"; + break; + case NotificationLevel::Debug: + level_string_ = "Debug"; + break; + case NotificationLevel::Info: + level_string_ = "Info"; + break; + case NotificationLevel::Warn: + level_string_ = "Warn"; + break; + case NotificationLevel::Error: + level_string_ = "Error"; + break; + default: + throw std::runtime_error("NotifierBuf invalid notification level"); + } +} + int NotifierBuf::sync() { - // NotificationType type = NotificationType::Info; - // notification_signal_(type, this->str()); if (sink_ && !this->str().empty()) - (*sink_) << this->str(); - + { + if (add_formatting_) + { + (*sink_) << getTime() << " [" << level_string_ << "] " << name_ << ": " << this->str(); + } + else + { + (*sink_) << this->str(); + } + } + this->str(""); return 0; } -Notifier::Notifier() +NotifierStream::NotifierStream(std::string name, NotificationLevel level) +: buf_(name, level) +{ + this->rdbuf(&buf_); +} + +Notifier::Notifier(std::string name) +: error(name, NotificationLevel::Error) +, warn(name, NotificationLevel::Warn) +, info(name, NotificationLevel::Info) +, debug(name, NotificationLevel::Debug) +, trace(name, NotificationLevel::Trace) { // default to Info & Warn on cout and Error on cerr SetSinks(&std::cout, NotificationLevel::Info, NotificationLevel::Warn); @@ -69,4 +125,13 @@ void Notifier::ClearSinks(NotificationLevel minLevel, NotificationLevel maxLevel void Notifier::ClearSink(NotificationLevel level) { ClearSinks(level, level); +} + +void Notifier::EnableFormatting(bool enable) +{ + trace.EnableFormatting(enable); + debug.EnableFormatting(enable); + info.EnableFormatting(enable); + warn.EnableFormatting(enable); + error.EnableFormatting(enable); } \ No newline at end of file From f574b62f4302efd1cd53b6bece4c42cc7d7815e3 Mon Sep 17 00:00:00 2001 From: Ross Taylor Date: Tue, 18 May 2021 18:54:33 -0500 Subject: [PATCH 6/8] Update: improve output clarity --- src/client/device_info.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/device_info.cpp b/src/client/device_info.cpp index 3842d03..ed74acf 100644 --- a/src/client/device_info.cpp +++ b/src/client/device_info.cpp @@ -28,7 +28,7 @@ DeviceInfo::DeviceInfo(const std::string& host) std::stringstream device_info_stream; // get deviceInfo from sensor for calibration - quanergy::log.info << "Attempting to get device info from " << host << std::endl; + quanergy::log.info << "Attempting to get device info from " << host << "..." << std::endl; http_client.read(device_info_path_, device_info_stream); boost::property_tree::ptree device_info_tree; boost::property_tree::read_xml(device_info_stream, device_info_tree); @@ -66,7 +66,7 @@ DeviceInfo::DeviceInfo(const std::string& host) } // if laser data } // if cal data - quanergy::log.info << "... complete." << std::endl; + quanergy::log.info << "Device info retrieval complete." << std::endl; } // constructor From bd3cb1347afdb033302787663403960edfc3d997 Mon Sep 17 00:00:00 2001 From: Ross Taylor Date: Tue, 18 May 2021 18:59:33 -0500 Subject: [PATCH 7/8] Update: clean up output messages --- include/quanergy/client/impl/tcp_client.hpp | 2 +- include/quanergy/pipelines/async.h | 2 +- src/parsers/data_packet_parser_m_series.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/quanergy/client/impl/tcp_client.hpp b/include/quanergy/client/impl/tcp_client.hpp index 774caa5..a78446a 100755 --- a/include/quanergy/client/impl/tcp_client.hpp +++ b/include/quanergy/client/impl/tcp_client.hpp @@ -230,7 +230,7 @@ namespace quanergy while (buff_queue_.size() > max_queue_size_) { buff_queue_.pop(); - log.warn << "Warning: Client dropped packet due to full buffer" << std::endl; + log.warn << "Client dropped packet due to full buffer" << std::endl; } lk.unlock(); diff --git a/include/quanergy/pipelines/async.h b/include/quanergy/pipelines/async.h index 0d942d6..5437f15 100644 --- a/include/quanergy/pipelines/async.h +++ b/include/quanergy/pipelines/async.h @@ -90,7 +90,7 @@ namespace quanergy // while shouldn't be necessary but doesn't hurt just to be sure while (input_queue_.size() > max_queue_size_) { - log.warn << "Warning: AsyncModule dropped input due to full buffer" << std::endl; + log.warn << "AsyncModule dropped input due to full buffer" << std::endl; input_queue_.pop(); } diff --git a/src/parsers/data_packet_parser_m_series.cpp b/src/parsers/data_packet_parser_m_series.cpp index 6c10e7a..7a14a0f 100644 --- a/src/parsers/data_packet_parser_m_series.cpp +++ b/src/parsers/data_packet_parser_m_series.cpp @@ -193,7 +193,7 @@ namespace quanergy if(cloudfull) { - log.warn << "Warning: Maximum cloud size limit of (" + log.warn << "Maximum cloud size limit of (" << maximum_cloud_size_ << ") exceeded" << std::endl; } @@ -219,7 +219,7 @@ namespace quanergy } else if(current_cloud_->size() > 0) { - log.warn << "Warning: Minimum cloud size limit of (" << minimum_cloud_size_ + log.warn << "Minimum cloud size limit of (" << minimum_cloud_size_ << ") not reached (" << current_cloud_->size() << ")" << std::endl; } From c5d3290ed51ff6e6661591be036a0cdecea16195 Mon Sep 17 00:00:00 2001 From: Ross Taylor Date: Thu, 20 May 2021 11:06:21 -0500 Subject: [PATCH 8/8] fix: Windows build failure --- src/common/notifications.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp index e619355..f50d1a9 100644 --- a/src/common/notifications.cpp +++ b/src/common/notifications.cpp @@ -71,7 +71,8 @@ int NotifierBuf::sync() } NotifierStream::NotifierStream(std::string name, NotificationLevel level) -: buf_(name, level) +: std::ostream(nullptr) +, buf_(name, level) { this->rdbuf(&buf_); }