mirror of
https://github.com/MrUnknownDE/OpenIris-ESPIDF.git
synced 2026-05-02 20:36:04 +02:00
- Updated README to reflect changes in device mode terminology from "Auto" to "Setup".
- Changed configuration macros from CONFIG_GENERAL_DEFAULT_WIRED_MODE to CONFIG_GENERAL_INCLUDE_UVC_MODE across multiple files. - Introduced new command for retrieving LED current in CommandManager. - Added MonitoringManager and CurrentMonitor classes to handle LED current monitoring. - Updated Kconfig to include options for LED current monitoring. - Modified main application logic to integrate MonitoringManager and handle new device modes. - Adjusted CMakeLists and source files to include new monitoring components.
This commit is contained in:
@@ -48,7 +48,7 @@ void CameraManager::setupCameraPinout()
|
||||
|
||||
ESP_LOGI(CAMERA_MANAGER_TAG, "CAM_BOARD");
|
||||
#endif
|
||||
#if CONFIG_GENERAL_DEFAULT_WIRED_MODE
|
||||
#if CONFIG_GENERAL_INCLUDE_UVC_MODE
|
||||
xclk_freq_hz = CONFIG_CAMERA_USB_XCLK_FREQ;
|
||||
#endif
|
||||
|
||||
@@ -196,7 +196,7 @@ bool CameraManager::setupCamera()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if CONFIG_GENERAL_DEFAULT_WIRED_MODE
|
||||
#if CONFIG_GENERAL_INCLUDE_UVC_MODE
|
||||
const auto temp_sensor = esp_camera_sensor_get();
|
||||
|
||||
// Thanks to lick_it, we discovered that OV5640 likes to overheat when
|
||||
|
||||
@@ -11,5 +11,5 @@ idf_component_register(
|
||||
INCLUDE_DIRS
|
||||
"CommandManager"
|
||||
"CommandManager/commands"
|
||||
REQUIRES ProjectConfig cJSON CameraManager OpenIrisTasks wifiManager Helpers LEDManager
|
||||
REQUIRES ProjectConfig cJSON CameraManager OpenIrisTasks wifiManager Helpers LEDManager Monitoring
|
||||
)
|
||||
@@ -26,6 +26,7 @@ std::unordered_map<std::string, CommandType> commandTypeMap = {
|
||||
{"set_led_duty_cycle", CommandType::SET_LED_DUTY_CYCLE},
|
||||
{"get_led_duty_cycle", CommandType::GET_LED_DUTY_CYCLE},
|
||||
{"get_serial", CommandType::GET_SERIAL},
|
||||
{"get_led_current", CommandType::GET_LED_CURRENT},
|
||||
};
|
||||
|
||||
std::function<CommandResult()> CommandManager::createCommand(const CommandType type, std::string_view json) const
|
||||
@@ -103,6 +104,9 @@ std::function<CommandResult()> CommandManager::createCommand(const CommandType t
|
||||
case CommandType::GET_SERIAL:
|
||||
return [this]
|
||||
{ return getSerialNumberCommand(this->registry); };
|
||||
case CommandType::GET_LED_CURRENT:
|
||||
return [this]
|
||||
{ return getLEDCurrentCommand(this->registry); };
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ enum class CommandType
|
||||
SET_LED_DUTY_CYCLE,
|
||||
GET_LED_DUTY_CYCLE,
|
||||
GET_SERIAL,
|
||||
GET_LED_CURRENT,
|
||||
};
|
||||
|
||||
class CommandManager
|
||||
|
||||
@@ -9,7 +9,8 @@ enum class DependencyType
|
||||
project_config,
|
||||
camera_manager,
|
||||
wifi_manager,
|
||||
led_manager
|
||||
led_manager,
|
||||
monitoring_manager
|
||||
};
|
||||
|
||||
class DependencyRegistry
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "device_commands.hpp"
|
||||
#include "LEDManager.hpp"
|
||||
#include "MonitoringManager.hpp"
|
||||
#include "esp_mac.h"
|
||||
#include <cstdio>
|
||||
|
||||
@@ -171,9 +172,9 @@ CommandResult switchModeCommand(std::shared_ptr<DependencyRegistry> registry, st
|
||||
{
|
||||
newMode = StreamingMode::WIFI;
|
||||
}
|
||||
else if (strcmp(modeStr, "auto") == 0)
|
||||
else if (strcmp(modeStr, "setup") == 0 || strcmp(modeStr, "auto") == 0)
|
||||
{
|
||||
newMode = StreamingMode::AUTO;
|
||||
newMode = StreamingMode::SETUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -203,8 +204,8 @@ CommandResult getDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry)
|
||||
case StreamingMode::WIFI:
|
||||
modeStr = "WiFi";
|
||||
break;
|
||||
case StreamingMode::AUTO:
|
||||
modeStr = "Auto";
|
||||
case StreamingMode::SETUP:
|
||||
modeStr = "Setup";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -231,3 +232,19 @@ CommandResult getSerialNumberCommand(std::shared_ptr<DependencyRegistry> /*regis
|
||||
auto result = std::format("{{ \"serial\": \"{}\", \"mac\": \"{}\" }}", serial_no_sep, mac_colon);
|
||||
return CommandResult::getSuccessResult(result);
|
||||
}
|
||||
|
||||
CommandResult getLEDCurrentCommand(std::shared_ptr<DependencyRegistry> registry)
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
auto mon = registry->resolve<MonitoringManager>(DependencyType::monitoring_manager);
|
||||
if (!mon)
|
||||
{
|
||||
return CommandResult::getErrorResult("MonitoringManager unavailable");
|
||||
}
|
||||
float ma = mon->getCurrentMilliAmps();
|
||||
auto result = std::format("{{ \"led_current_ma\": {:.3f} }}", static_cast<double>(ma));
|
||||
return CommandResult::getSuccessResult(result);
|
||||
#else
|
||||
return CommandResult::getErrorResult("Monitoring disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -22,4 +22,7 @@ CommandResult switchModeCommand(std::shared_ptr<DependencyRegistry> registry, st
|
||||
|
||||
CommandResult getDeviceModeCommand(std::shared_ptr<DependencyRegistry> registry);
|
||||
|
||||
CommandResult getSerialNumberCommand(std::shared_ptr<DependencyRegistry> registry);
|
||||
CommandResult getSerialNumberCommand(std::shared_ptr<DependencyRegistry> registry);
|
||||
|
||||
// Monitoring
|
||||
CommandResult getLEDCurrentCommand(std::shared_ptr<DependencyRegistry> registry);
|
||||
@@ -0,0 +1,6 @@
|
||||
idf_component_register(SRCS
|
||||
"Monitoring/CurrentMonitor.cpp"
|
||||
"Monitoring/MonitoringManager.cpp"
|
||||
INCLUDE_DIRS "Monitoring"
|
||||
REQUIRES driver esp_adc Helpers
|
||||
)
|
||||
@@ -0,0 +1,179 @@
|
||||
#include "CurrentMonitor.hpp"
|
||||
#include <esp_log.h>
|
||||
#include <cmath>
|
||||
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG_CM = "[CurrentMonitor]";
|
||||
|
||||
CurrentMonitor::CurrentMonitor()
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
samples_.assign(CONFIG_MONITORING_LED_SAMPLES, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CurrentMonitor::setup()
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
init_adc();
|
||||
#else
|
||||
ESP_LOGI(TAG_CM, "LED current monitoring disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
float CurrentMonitor::getCurrentMilliAmps() const
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
const int shunt_milliohm = CONFIG_MONITORING_LED_SHUNT_MILLIOHM; // mΩ
|
||||
if (shunt_milliohm <= 0)
|
||||
return 0.0f;
|
||||
// Physically correct scaling:
|
||||
// I[mA] = 1000 * Vshunt[mV] / R[mΩ]
|
||||
return (1000.0f * static_cast<float>(filtered_mv_)) / static_cast<float>(shunt_milliohm);
|
||||
#else
|
||||
return 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
float CurrentMonitor::pollAndGetMilliAmps()
|
||||
{
|
||||
sampleOnce();
|
||||
return getCurrentMilliAmps();
|
||||
}
|
||||
|
||||
void CurrentMonitor::sampleOnce()
|
||||
{
|
||||
#if 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<int>(sample_count_ > 0 ? sample_count_ : 1);
|
||||
#else
|
||||
(void)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 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<adc_channel_t>(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
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
class CurrentMonitor {
|
||||
public:
|
||||
CurrentMonitor();
|
||||
~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();
|
||||
|
||||
// Whether monitoring is enabled by Kconfig
|
||||
static constexpr bool isEnabled()
|
||||
{
|
||||
#ifdef CONFIG_MONITORING_LED_CURRENT
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if 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<int> samples_;
|
||||
size_t sample_idx_ = 0;
|
||||
size_t sample_count_ = 0;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "MonitoringManager.hpp"
|
||||
#include <esp_log.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char* TAG_MM = "[MonitoringManager]";
|
||||
|
||||
void MonitoringManager::setup()
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
cm_.setup();
|
||||
ESP_LOGI(TAG_MM, "Monitoring enabled. Interval=%dms, Samples=%d, Gain=%d, R=%dmΩ",
|
||||
CONFIG_MONITORING_LED_INTERVAL_MS,
|
||||
CONFIG_MONITORING_LED_SAMPLES,
|
||||
CONFIG_MONITORING_LED_GAIN,
|
||||
CONFIG_MONITORING_LED_SHUNT_MILLIOHM);
|
||||
#else
|
||||
ESP_LOGI(TAG_MM, "Monitoring disabled by Kconfig");
|
||||
#endif
|
||||
}
|
||||
|
||||
void MonitoringManager::start()
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
if (task_ == nullptr)
|
||||
{
|
||||
xTaskCreate(&MonitoringManager::taskEntry, "MonitoringTask", 2048, this, 1, &task_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MonitoringManager::stop()
|
||||
{
|
||||
if (task_)
|
||||
{
|
||||
TaskHandle_t toDelete = task_;
|
||||
task_ = nullptr;
|
||||
vTaskDelete(toDelete);
|
||||
}
|
||||
}
|
||||
|
||||
void MonitoringManager::taskEntry(void* arg)
|
||||
{
|
||||
static_cast<MonitoringManager*>(arg)->run();
|
||||
}
|
||||
|
||||
void MonitoringManager::run()
|
||||
{
|
||||
#if CONFIG_MONITORING_LED_CURRENT
|
||||
while (true)
|
||||
{
|
||||
float ma = cm_.pollAndGetMilliAmps();
|
||||
last_current_ma_.store(ma);
|
||||
vTaskDelay(pdMS_TO_TICKS(CONFIG_MONITORING_LED_INTERVAL_MS));
|
||||
}
|
||||
#else
|
||||
vTaskDelete(nullptr);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <atomic>
|
||||
#include "CurrentMonitor.hpp"
|
||||
|
||||
class MonitoringManager {
|
||||
public:
|
||||
MonitoringManager() = default;
|
||||
~MonitoringManager() = default;
|
||||
|
||||
void setup();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
// Latest filtered current in mA
|
||||
float getCurrentMilliAmps() const { return last_current_ma_.load(); }
|
||||
|
||||
private:
|
||||
static void taskEntry(void* arg);
|
||||
void run();
|
||||
|
||||
TaskHandle_t task_{nullptr};
|
||||
std::atomic<float> last_current_ma_{0.0f};
|
||||
CurrentMonitor cm_;
|
||||
};
|
||||
@@ -23,7 +23,7 @@ struct BaseConfigModel
|
||||
|
||||
enum class StreamingMode
|
||||
{
|
||||
AUTO,
|
||||
SETUP,
|
||||
UVC,
|
||||
WIFI,
|
||||
};
|
||||
@@ -31,18 +31,18 @@ enum class StreamingMode
|
||||
struct DeviceMode_t : BaseConfigModel
|
||||
{
|
||||
StreamingMode mode;
|
||||
explicit DeviceMode_t(Preferences *pref) : BaseConfigModel(pref), mode(StreamingMode::AUTO) {}
|
||||
explicit DeviceMode_t(Preferences *pref) : BaseConfigModel(pref), mode(StreamingMode::SETUP) {}
|
||||
|
||||
void load()
|
||||
{
|
||||
// Default mode can be controlled via sdkconfig:
|
||||
// - If CONFIG_START_IN_UVC_MODE is enabled, default to UVC
|
||||
// - Otherwise default to AUTO
|
||||
// Default mode can be controlled via sdkconfig:
|
||||
// - If CONFIG_START_IN_UVC_MODE is enabled, default to UVC
|
||||
// - Otherwise default to SETUP
|
||||
int default_mode =
|
||||
#if CONFIG_START_IN_UVC_MODE
|
||||
static_cast<int>(StreamingMode::UVC);
|
||||
#else
|
||||
static_cast<int>(StreamingMode::AUTO);
|
||||
static_cast<int>(StreamingMode::SETUP);
|
||||
#endif
|
||||
|
||||
int stored_mode = this->pref->getInt("mode", default_mode);
|
||||
|
||||
@@ -159,7 +159,7 @@ static void UVCStreamHelpers::camera_fb_return_cb(uvc_fb_t *fb, void *cb_ctx)
|
||||
esp_err_t UVCStreamManager::setup()
|
||||
{
|
||||
|
||||
#ifndef CONFIG_GENERAL_DEFAULT_WIRED_MODE
|
||||
#ifndef CONFIG_GENERAL_INCLUDE_UVC_MODE
|
||||
ESP_LOGE(UVC_STREAM_TAG, "The board does not support UVC, please, setup WiFi connection.");
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user