From 01c48dae3eec4dd88227fc5818a4baec0c6eb37f Mon Sep 17 00:00:00 2001 From: arades79 Date: Fri, 10 Dec 2021 12:37:44 -0500 Subject: [PATCH] Centralized interval reporter (#10) * create centralized interval reporter, use reporter for opt surf probe * use arduino channels instead of STM * remove state tracking * refactor to eliminate more variables, use optionals, and support more channels * change interval report interface * simplify and remove some STL dependencies * add config flags * separate declarations and definitions --- Marlin/Configuration_adv.h | 7 ++ Marlin/src/feature/interval_reporter.cpp | 67 ++++++++++++++++++++ Marlin/src/feature/interval_reporter.h | 51 +++++++++++++++ Marlin/src/feature/optical_surface_probe.cpp | 9 ++- Marlin/src/feature/optical_surface_probe.h | 52 ++++++++------- 5 files changed, 160 insertions(+), 26 deletions(-) create mode 100644 Marlin/src/feature/interval_reporter.cpp create mode 100644 Marlin/src/feature/interval_reporter.h diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index d3dd3854daa66..22854278cda9f 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -4263,6 +4263,13 @@ #define ____HELLO____ :) #endif +//#define GLOBAL_INTERVAL_REPORTER +#if ENABLED(GLOBAL_INTERVAL_REPORTER) + #define INTERVAL_REPORTER_TIMER TIM12 + #define NUM_INTERVAL_REPORTER_SLOTS 4 + #define INTERVAL_REPORTER_DEFAULT_INTERVAL 1'000'000 +#endif + // @section develop // diff --git a/Marlin/src/feature/interval_reporter.cpp b/Marlin/src/feature/interval_reporter.cpp new file mode 100644 index 0000000000000..0415302a605d6 --- /dev/null +++ b/Marlin/src/feature/interval_reporter.cpp @@ -0,0 +1,67 @@ +#include "../inc/MarlinConfig.h" + + +#if ENABLED(GLOBAL_INTERVAL_REPORTER) + + + #include "interval_reporter.h" + + IntervalReporter::IntervalReporter(callback_function_t reporter) : channel(nullptr) + { + for (auto &reporter_slot : reporters) + { + if (!reporter_slot.valid) + { + reporter_slot = Reporter(reporter); + channel = &reporter_slot; + break; + } + } + + if (!channel) + { + SERIAL_ERROR_MSG("Too many reporters registered! Some reports will not appear!"); + return; + } + + refresh(); + } + + IntervalReporter::~IntervalReporter() + { + if (channel) + { + channel->valid = false; + channel->enabled = false; + } + } + + void IntervalReporter::set_interval_us(const uint32_t interval_us) + { + timer.setOverflow(interval_us, TimerFormat_t::MICROSEC_FORMAT); + refresh(); + } + + void IntervalReporter::report_all() + { + for (const auto &reporter : reporters) + if (reporter.enabled) + reporter.fn(); + } + + void IntervalReporter::refresh() + { + timer.pause(); + timer.refresh(); + timer.resume(); + } + + HardwareTimer IntervalReporter::timer{[]() { + HardwareTimer timer{INTERVAL_REPORTER_TIMER}; + timer.setOverflow(INTERVAL_REPORTER_DEFAULT_INTERVAL, TimerFormat_t::MICROSEC_FORMAT); + timer.attachInterrupt(IntervalReporter::report_all); + return timer; + }()}; + IntervalReporter::ReporterArray IntervalReporter::reporters{}; + +#endif // GLOBAL_INTERVAL_REPORTER \ No newline at end of file diff --git a/Marlin/src/feature/interval_reporter.h b/Marlin/src/feature/interval_reporter.h new file mode 100644 index 0000000000000..b9dbd9748d70a --- /dev/null +++ b/Marlin/src/feature/interval_reporter.h @@ -0,0 +1,51 @@ +#pragma once + +#include "../inc/MarlinConfig.h" + +#include + +struct IntervalReporter +{ + + explicit IntervalReporter(callback_function_t reporter); + + ~IntervalReporter(); + + inline void start() { if (channel) channel->enabled = true; } + + inline void stop() { if (channel) channel->enabled = false; } + + inline static const uint32_t get_interval_ms() { return get_interval_us() / 1000UL; } + + inline static const uint32_t get_interval_us() { + return timer.getOverflow(TimerFormat_t::MICROSEC_FORMAT); + } + + inline static void set_interval_ms(const uint32_t interval_ms) { + set_interval_us(interval_ms * 1000); + } + + static void set_interval_us(const uint32_t interval_us); + +private: + static HardwareTimer timer; + + struct Reporter + { + bool valid; + bool enabled; + callback_function_t fn; + + Reporter() = default; + explicit Reporter(callback_function_t fn) : valid(true), fn(fn) {} + }; + + Reporter * channel; + + using ReporterArray = std::array; + static ReporterArray reporters; + + static void report_all(); + + static void refresh(); +}; \ No newline at end of file diff --git a/Marlin/src/feature/optical_surface_probe.cpp b/Marlin/src/feature/optical_surface_probe.cpp index b006dd8c56540..b87b6a65d171b 100644 --- a/Marlin/src/feature/optical_surface_probe.cpp +++ b/Marlin/src/feature/optical_surface_probe.cpp @@ -12,8 +12,13 @@ const auto val = probe.get_distance(); SERIAL_ECHOLNPAIR("Probe raw reading: ", val); - const auto ms = parser.intval('P', 0); - probe.interval_report(ms); + #if ENABLED(GLOBAL_INTERVAL_REPORTER) + const auto ms = parser.intval('P', 0); + if (ms > 0) IntervalReporter::set_interval_ms(ms); + + const auto start = parser.boolval('S'); + probe.interval_report(start); + #endif } #endif // OPTICAL_SURFACE_PROBE \ No newline at end of file diff --git a/Marlin/src/feature/optical_surface_probe.h b/Marlin/src/feature/optical_surface_probe.h index ab1d13ab934ff..a9a104ac4f086 100644 --- a/Marlin/src/feature/optical_surface_probe.h +++ b/Marlin/src/feature/optical_surface_probe.h @@ -4,6 +4,10 @@ #include "../module/planner.h" +#if ENABLED(GLOBAL_INTERVAL_REPORTER) + #include "interval_reporter.h" +#endif + #include // using namespace std::string_view_literals; @@ -19,34 +23,26 @@ struct OpticalSurfaceProbe void init(); - const auto get_distance() const + const uint32_t get_distance() const { return analogRead(OPT_SURF_IN_PIN); } - /** - * @brief reports analog sensor reading at a set interval - * using a hardware timer based interrupt - * - * @param ms milliseconds between reports - */ - void interval_report(const int ms) - { - // requires static lifetime for interrupts to trigger, - // and to ensure we can stop the timer later. - static HardwareTimer timer{TIM12}; - timer.pause(); - if (ms <= 0) - return; - - timer.setOverflow(ms * 1000, TimerFormat_t::MICROSEC_FORMAT); - timer.attachInterrupt([this] - { - const auto position = planner.get_axis_positions_mm(); - SERIAL_ECHOLNPAIR("prb:", get_distance(), ",X:", position.x, ",Y:", position.y, ",Z:", position.z); - }); - timer.resume(); - } + #if ENABLED(GLOBAL_INTERVAL_REPORTER) + /** + * @brief reports analog sensor reading at a set interval + * using a hardware timer based interrupt + * + * @param ms milliseconds between reports + */ + void interval_report(bool start) + { + if (start) + reporter.start(); + else + reporter.stop(); + } + #endif /** * @brief TODO: unimplemented, intended to alter sensor angle @@ -63,6 +59,14 @@ struct OpticalSurfaceProbe private: constexpr static size_t READ_BUFFER_SIZE{255}; + #if ENABLED(GLOBAL_INTERVAL_REPORTER) + IntervalReporter reporter{[this] + { + const auto position = planner.get_axis_positions_mm(); + SERIAL_ECHOLNPAIR("prb:", get_distance(), ",X:", position.x, ",Y:", position.y, ",Z:", position.z); + }}; + #endif + /** * @brief Private inner struct for holding serial communication * protocols and other sensor specific implementation details