diff --git a/components/Monitoring/Monitoring/CurrentMonitor.hpp b/components/Monitoring/Monitoring/CurrentMonitor.hpp index f61fa01..6cfdea0 100644 --- a/components/Monitoring/Monitoring/CurrentMonitor.hpp +++ b/components/Monitoring/Monitoring/CurrentMonitor.hpp @@ -3,25 +3,19 @@ #pragma once #include #include -#include #include "sdkconfig.h" +#include "AdcSampler.hpp" class CurrentMonitor { public: - CurrentMonitor(); + CurrentMonitor() = default; ~CurrentMonitor() = default; void setup(); - void sampleOnce(); - - // Returns filtered voltage in millivolts at shunt (after dividing by gain) - int getFilteredMillivolts() const { return filtered_mv_; } - // Returns current in milliamps computed as Vshunt[mV] / R[mΩ] - float getCurrentMilliAmps() const; // convenience: combined sampling and compute; returns mA - float pollAndGetMilliAmps(); + float getCurrentMilliAmps() const; // Whether monitoring is enabled by Kconfig static constexpr bool isEnabled() @@ -34,17 +28,7 @@ public: } private: -#ifdef CONFIG_MONITORING_LED_CURRENT - void init_adc(); - int read_mv_once(); - int gpio_to_adc_channel(int gpio); -#endif - - int filtered_mv_ = 0; - int sample_sum_ = 0; - std::vector samples_; - size_t sample_idx_ = 0; - size_t sample_count_ = 0; + mutable AdcSampler adc_; }; #endif diff --git a/components/Monitoring/Monitoring/CurrentMonitor_esp32s3.cpp b/components/Monitoring/Monitoring/CurrentMonitor_esp32s3.cpp index 478a7ce..c041a01 100644 --- a/components/Monitoring/Monitoring/CurrentMonitor_esp32s3.cpp +++ b/components/Monitoring/Monitoring/CurrentMonitor_esp32s3.cpp @@ -1,26 +1,17 @@ -#include "CurrentMonitor.hpp" #include #include - -#ifdef CONFIG_MONITORING_LED_CURRENT -#include "esp_adc/adc_oneshot.h" -#include "esp_adc/adc_cali.h" -#include "esp_adc/adc_cali_scheme.h" -#endif +#include "CurrentMonitor.hpp" static const char *TAG_CM = "[CurrentMonitor]"; -CurrentMonitor::CurrentMonitor() -{ -#ifdef CONFIG_MONITORING_LED_CURRENT - samples_.assign(CONFIG_MONITORING_LED_SAMPLES, 0); -#endif -} - void CurrentMonitor::setup() { #ifdef CONFIG_MONITORING_LED_CURRENT - init_adc(); + const bool ok = adc_.init(CONFIG_MONITORING_LED_ADC_GPIO, ADC_ATTEN_DB_12, ADC_BITWIDTH_DEFAULT, CONFIG_MONITORING_LED_SAMPLES); + if (!ok) + { + ESP_LOGE(TAG_CM, "ADC init failed for LED current monitor"); + } #else ESP_LOGI(TAG_CM, "LED current monitoring disabled"); #endif @@ -32,148 +23,18 @@ float CurrentMonitor::getCurrentMilliAmps() const const int shunt_milliohm = CONFIG_MONITORING_LED_SHUNT_MILLIOHM; // mΩ if (shunt_milliohm <= 0) return 0.0f; + + if (!adc_.sampleOnce()) + return 0.0f; + + int filtered_mv = adc_.getFilteredMilliVolts(); + if (CONFIG_MONITORING_LED_GAIN > 0) + filtered_mv = filtered_mv / CONFIG_MONITORING_LED_GAIN; // convert back to shunt voltage + // Physically correct scaling: // I[mA] = 1000 * Vshunt[mV] / R[mΩ] - return (1000.0f * static_cast(filtered_mv_)) / static_cast(shunt_milliohm); + return (1000.0f * static_cast(filtered_mv)) / static_cast(shunt_milliohm); #else return 0.0f; #endif -} - -float CurrentMonitor::pollAndGetMilliAmps() -{ - sampleOnce(); - return getCurrentMilliAmps(); -} - -void CurrentMonitor::sampleOnce() -{ -#ifdef CONFIG_MONITORING_LED_CURRENT - int mv = read_mv_once(); - // Divide by analog gain/divider factor to get shunt voltage - if (CONFIG_MONITORING_LED_GAIN > 0) - mv = mv / CONFIG_MONITORING_LED_GAIN; - - // Moving average over N samples - if (samples_.empty()) - { - samples_.assign(CONFIG_MONITORING_LED_SAMPLES, 0); - sample_sum_ = 0; - sample_idx_ = 0; - sample_count_ = 0; - } - - sample_sum_ -= samples_[sample_idx_]; - samples_[sample_idx_] = mv; - sample_sum_ += mv; - sample_idx_ = (sample_idx_ + 1) % samples_.size(); - if (sample_count_ < samples_.size()) - sample_count_++; - - filtered_mv_ = sample_sum_ / static_cast(sample_count_ > 0 ? sample_count_ : 1); -#else - (void)0; -#endif -} - -#ifdef CONFIG_MONITORING_LED_CURRENT - -static adc_oneshot_unit_handle_t s_adc_handle = nullptr; -static adc_cali_handle_t s_cali_handle = nullptr; -static bool s_cali_inited = false; -static adc_channel_t s_channel; -static adc_unit_t s_unit; - -void CurrentMonitor::init_adc() -{ - // Derive ADC unit/channel from GPIO - int gpio = CONFIG_MONITORING_LED_ADC_GPIO; - - esp_err_t err; - adc_oneshot_unit_init_cfg_t unit_cfg = { - .unit_id = ADC_UNIT_1, - }; - err = adc_oneshot_new_unit(&unit_cfg, &s_adc_handle); - if (err != ESP_OK) - { - ESP_LOGE(TAG_CM, "adc_oneshot_new_unit failed: %s", esp_err_to_name(err)); - return; - } - - // Try to map GPIO to ADC channel automatically if helper exists; otherwise guess for ESP32-S3 ADC1 -#ifdef ADC1_GPIO1_CHANNEL - (void)0; // placeholder for potential future macros -#endif - - // Use IO-to-channel helper where available -#ifdef CONFIG_IDF_TARGET_ESP32S3 - // ESP32-S3: ADC1 channels on GPIO1..GPIO10 map to CH0..CH9 - if (gpio >= 1 && gpio <= 10) - { - s_unit = ADC_UNIT_1; - s_channel = static_cast(gpio - 1); - } - else - { - ESP_LOGW(TAG_CM, "Configured GPIO %d may not be ADC-capable on ESP32-S3", gpio); - s_unit = ADC_UNIT_1; - s_channel = ADC_CHANNEL_0; - } -#else - // Fallback: assume ADC1 CH0 - s_unit = ADC_UNIT_1; - s_channel = ADC_CHANNEL_0; -#endif - - adc_oneshot_chan_cfg_t chan_cfg = { - .atten = ADC_ATTEN_DB_11, - .bitwidth = ADC_BITWIDTH_DEFAULT, - }; - err = adc_oneshot_config_channel(s_adc_handle, s_channel, &chan_cfg); - if (err != ESP_OK) - { - ESP_LOGE(TAG_CM, "adc_oneshot_config_channel failed: %s", esp_err_to_name(err)); - } - - // Calibration using curve fitting if available - adc_cali_curve_fitting_config_t cal_cfg = { - .unit_id = s_unit, - .atten = chan_cfg.atten, - .bitwidth = chan_cfg.bitwidth, - }; - if (adc_cali_create_scheme_curve_fitting(&cal_cfg, &s_cali_handle) == ESP_OK) - { - s_cali_inited = true; - ESP_LOGI(TAG_CM, "ADC calibration initialized (curve fitting)"); - } - else - { - s_cali_inited = false; - ESP_LOGW(TAG_CM, "ADC calibration not available; using raw-to-mV approximation"); - } -} - -int CurrentMonitor::read_mv_once() -{ - if (!s_adc_handle) - return 0; - int raw = 0; - if (adc_oneshot_read(s_adc_handle, s_channel, &raw) != ESP_OK) - return 0; - - int mv = 0; - if (s_cali_inited) - { - if (adc_cali_raw_to_voltage(s_cali_handle, raw, &mv) != ESP_OK) - mv = 0; - } - else - { - // Very rough fallback for 11dB attenuation - // Typical full-scale ~2450mV at raw max 4095 (12-bit). IDF defaults may vary. - mv = (raw * 2450) / 4095; - } - return mv; -} - -#endif // CONFIG_MONITORING_LED_CURRENT +} \ No newline at end of file