mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 23:21:54 +00:00 
			
		
		
		
	removed power management
This commit is contained in:
		| @@ -11,6 +11,7 @@ import esphome.codegen as cg | |||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.core import coroutine_with_priority | from esphome.core import coroutine_with_priority | ||||||
| from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option | from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option | ||||||
|  | from esphome.components.binary_sensor import BinarySensor | ||||||
|  |  | ||||||
| CODEOWNERS = ["@oarcher"] | CODEOWNERS = ["@oarcher"] | ||||||
| DEPENDENCIES = ["esp32"] | DEPENDENCIES = ["esp32"] | ||||||
| @@ -23,6 +24,7 @@ CONF_APN = "apn" | |||||||
| CONF_STATUS_PIN = "status_pin" | CONF_STATUS_PIN = "status_pin" | ||||||
| CONF_DTR_PIN = "dtr_pin" | CONF_DTR_PIN = "dtr_pin" | ||||||
| CONF_INIT_AT = "init_at" | CONF_INIT_AT = "init_at" | ||||||
|  | CONF_READY = "ready" | ||||||
|  |  | ||||||
|  |  | ||||||
| modem_ns = cg.esphome_ns.namespace("modem") | modem_ns = cg.esphome_ns.namespace("modem") | ||||||
| @@ -37,6 +39,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Required(CONF_RX_PIN): cv.positive_int, |             cv.Required(CONF_RX_PIN): cv.positive_int, | ||||||
|             cv.Required(CONF_MODEL): cv.string, |             cv.Required(CONF_MODEL): cv.string, | ||||||
|             cv.Required(CONF_APN): cv.string, |             cv.Required(CONF_APN): cv.string, | ||||||
|  |             cv.Optional(CONF_READY): cv.use_id(BinarySensor), | ||||||
|             cv.Optional(CONF_FLIGHT_PIN): cv.positive_int, |             cv.Optional(CONF_FLIGHT_PIN): cv.positive_int, | ||||||
|             cv.Optional(CONF_POWER_PIN): cv.positive_int, |             cv.Optional(CONF_POWER_PIN): cv.positive_int, | ||||||
|             cv.Optional(CONF_STATUS_PIN): cv.positive_int, |             cv.Optional(CONF_STATUS_PIN): cv.positive_int, | ||||||
| @@ -96,6 +99,10 @@ async def to_code(config): | |||||||
|         for cmd in init_at: |         for cmd in init_at: | ||||||
|             cg.add(var.add_init_at_command(cmd)) |             cg.add(var.add_init_at_command(cmd)) | ||||||
|  |  | ||||||
|  |     if modem_ready := config.get(CONF_READY, None): | ||||||
|  |         modem_ready_sensor = await cg.get_variable(modem_ready) | ||||||
|  |         cg.add(var.set_ready_bsensor(modem_ready_sensor)) | ||||||
|  |  | ||||||
|     cg.add(var.set_model(config[CONF_MODEL])) |     cg.add(var.set_model(config[CONF_MODEL])) | ||||||
|     cg.add(var.set_apn(config[CONF_APN])) |     cg.add(var.set_apn(config[CONF_APN])) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -74,13 +74,6 @@ bool ModemComponent::is_connected() { return this->state_ == ModemComponentState | |||||||
| void ModemComponent::setup() { | void ModemComponent::setup() { | ||||||
|   ESP_LOGI(TAG, "Setting up Modem..."); |   ESP_LOGI(TAG, "Setting up Modem..."); | ||||||
|  |  | ||||||
|   this->config_gpio_(); |  | ||||||
|  |  | ||||||
|   if (this->get_status()) { |  | ||||||
|     // at setup, the modem must be down |  | ||||||
|     this->powerdown(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   ESP_LOGV(TAG, "DTE setup"); |   ESP_LOGV(TAG, "DTE setup"); | ||||||
|   esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); |   esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); | ||||||
|   this->dte_config_ = dte_config; |   this->dte_config_ = dte_config; | ||||||
| @@ -152,30 +145,6 @@ void ModemComponent::setup() { | |||||||
|  |  | ||||||
|   assert(this->dce); |   assert(this->dce); | ||||||
|  |  | ||||||
|   this->poweron(); |  | ||||||
|  |  | ||||||
|   esp_modem::command_result res; |  | ||||||
|   res = this->dce->sync(); |  | ||||||
|   int retry = 0; |  | ||||||
|   while (res != command_result::OK) { |  | ||||||
|     res = this->dce->sync(); |  | ||||||
|     if (res != command_result::OK) { |  | ||||||
|       App.feed_wdt(); |  | ||||||
|       vTaskDelay(pdMS_TO_TICKS(1000)); |  | ||||||
|     } |  | ||||||
|     retry++; |  | ||||||
|     if (retry > 20) |  | ||||||
|       break; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // send initial AT commands from yaml |  | ||||||
|   for (const auto &cmd : this->init_at_commands_) { |  | ||||||
|     std::string result; |  | ||||||
|     command_result err = this->dce->at(cmd.c_str(), result, 1000); |  | ||||||
|     delay(100); |  | ||||||
|     ESP_LOGI(TAG, "Init AT command: %s (status %d) -> %s", cmd.c_str(), (int) err, result.c_str()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   this->started_ = true; |   this->started_ = true; | ||||||
|   ESP_LOGV(TAG, "Setup finished"); |   ESP_LOGV(TAG, "Setup finished"); | ||||||
| } | } | ||||||
| @@ -184,19 +153,9 @@ void ModemComponent::start_connect_() { | |||||||
|   this->connect_begin_ = millis(); |   this->connect_begin_ = millis(); | ||||||
|   this->status_set_warning("Starting connection"); |   this->status_set_warning("Starting connection"); | ||||||
|  |  | ||||||
|   if (!this->get_status()) { |  | ||||||
|     this->poweron(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // esp_err_t err; |  | ||||||
|   // err = esp_netif_set_hostname(this->ppp_netif_, App.get_name().c_str()); |  | ||||||
|   // if (err != ERR_OK) { |  | ||||||
|   //   ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err)); |  | ||||||
|   // } |  | ||||||
|  |  | ||||||
|   global_modem_component->got_ipv4_address_ = false;  // why not this ? |   global_modem_component->got_ipv4_address_ = false;  // why not this ? | ||||||
|  |  | ||||||
|   this->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND); |   this->dce->set_mode(modem_mode::COMMAND_MODE); | ||||||
|   vTaskDelay(pdMS_TO_TICKS(2000)); |   vTaskDelay(pdMS_TO_TICKS(2000)); | ||||||
|  |  | ||||||
|   command_result res = command_result::TIMEOUT; |   command_result res = command_result::TIMEOUT; | ||||||
| @@ -205,7 +164,6 @@ void ModemComponent::start_connect_() { | |||||||
|  |  | ||||||
|   if (res != command_result::OK) { |   if (res != command_result::OK) { | ||||||
|     ESP_LOGW(TAG, "Unable to sync modem. Will retry later"); |     ESP_LOGW(TAG, "Unable to sync modem. Will retry later"); | ||||||
|     this->powerdown(); |  | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -240,13 +198,20 @@ void ModemComponent::start_connect_() { | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   vTaskDelay(pdMS_TO_TICKS(2000)); |   vTaskDelay(pdMS_TO_TICKS(2000)); | ||||||
|  |  | ||||||
|  |   // send initial AT commands from yaml | ||||||
|  |   for (const auto &cmd : this->init_at_commands_) { | ||||||
|  |     std::string result; | ||||||
|  |     command_result err = this->dce->at(cmd.c_str(), result, 1000); | ||||||
|  |     delay(100); | ||||||
|  |     ESP_LOGI(TAG, "Init AT command: %s (status %d) -> %s", cmd.c_str(), (int) err, result.c_str()); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void ModemComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { | void ModemComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { | ||||||
|   ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; |   ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; | ||||||
|   const esp_netif_ip_info_t *ip_info = &event->ip_info; |   const esp_netif_ip_info_t *ip_info = &event->ip_info; | ||||||
|   ESP_LOGW(TAG, "[IP event] Got IP " IPSTR, IP2STR(&ip_info->ip)); |   ESP_LOGW(TAG, "[IP event] Got IP " IPSTR, IP2STR(&ip_info->ip)); | ||||||
|   vTaskDelay(pdMS_TO_TICKS(1000));  // FIXME tmp |  | ||||||
|   global_modem_component->got_ipv4_address_ = true; |   global_modem_component->got_ipv4_address_ = true; | ||||||
|   global_modem_component->connected_ = true; |   global_modem_component->connected_ = true; | ||||||
| } | } | ||||||
| @@ -257,14 +222,18 @@ void ModemComponent::loop() { | |||||||
|   switch (this->state_) { |   switch (this->state_) { | ||||||
|     case ModemComponentState::STOPPED: |     case ModemComponentState::STOPPED: | ||||||
|       if (this->started_) { |       if (this->started_) { | ||||||
|         ESP_LOGI(TAG, "Starting modem connection"); |         if (!this->modem_ready()) { | ||||||
|         this->state_ = ModemComponentState::CONNECTING; |           break; | ||||||
|         this->start_connect_(); |         } else { | ||||||
|  |           ESP_LOGI(TAG, "Starting modem connection"); | ||||||
|  |           this->state_ = ModemComponentState::CONNECTING; | ||||||
|  |           this->start_connect_(); | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|     case ModemComponentState::CONNECTING: |     case ModemComponentState::CONNECTING: | ||||||
|       if (!this->started_) { |       if (!this->started_) { | ||||||
|         ESP_LOGI(TAG, "Stopped ethernet connection"); |         ESP_LOGI(TAG, "Stopped modem connection"); | ||||||
|         this->state_ = ModemComponentState::STOPPED; |         this->state_ = ModemComponentState::STOPPED; | ||||||
|       } else if (this->connected_) { |       } else if (this->connected_) { | ||||||
|         // connection established |         // connection established | ||||||
| @@ -308,101 +277,6 @@ void ModemComponent::dump_connect_params_() { | |||||||
|   ESP_LOGCONFIG(TAG, "  DNS fallback: %s", network::IPAddress(dns_fallback_ip).str().c_str()); |   ESP_LOGCONFIG(TAG, "  DNS fallback: %s", network::IPAddress(dns_fallback_ip).str().c_str()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ModemComponent::config_gpio_() { |  | ||||||
|   ESP_LOGV(TAG, "Configuring GPIOs..."); |  | ||||||
|   gpio_config_t io_conf = {}; |  | ||||||
|   io_conf.intr_type = GPIO_INTR_DISABLE; |  | ||||||
|   io_conf.mode = GPIO_MODE_OUTPUT; |  | ||||||
|   io_conf.pin_bit_mask = 0ULL; |  | ||||||
|   if (this->power_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|     io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->power_pin_); |  | ||||||
|   } |  | ||||||
|   if (this->flight_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|     io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->flight_pin_); |  | ||||||
|   } |  | ||||||
|   if (this->dtr_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|     io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->dtr_pin_); |  | ||||||
|   } |  | ||||||
|   // io_conf.pin_bit_mask = ((1ULL << this->power_pin_) | (1ULL << this->flight_pin_)); |  | ||||||
|  |  | ||||||
|   io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; |  | ||||||
|   io_conf.pull_up_en = GPIO_PULLUP_DISABLE; |  | ||||||
|  |  | ||||||
|   gpio_config(&io_conf); |  | ||||||
|  |  | ||||||
|   io_conf.pin_bit_mask = 0ULL; |  | ||||||
|   if (this->status_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|     io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->status_pin_); |  | ||||||
|   } |  | ||||||
|   io_conf.mode = GPIO_MODE_INPUT; |  | ||||||
|   gpio_config(&io_conf); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ModemComponent::poweron() { |  | ||||||
|   ESP_LOGI(TAG, "Power on  modem"); |  | ||||||
|  |  | ||||||
|   if (this->get_status()) { |  | ||||||
|     ESP_LOGW(TAG, "modem is already on"); |  | ||||||
|   } else { |  | ||||||
|     // https://github.com/Xinyuan-LilyGO/LilyGO-T-SIM7000G/issues/251 |  | ||||||
|     if (this->power_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|       vTaskDelay(pdMS_TO_TICKS(1000)); |  | ||||||
|       ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 0));  // low = on, high = off |  | ||||||
|       vTaskDelay(pdMS_TO_TICKS(10)); |  | ||||||
|       ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 1)); |  | ||||||
|       vTaskDelay(pdMS_TO_TICKS(1010)); |  | ||||||
|       ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 0)); |  | ||||||
|       vTaskDelay(pdMS_TO_TICKS(4050));  // Ton uart 4.5sec but seems to need ~7sec after hard (button) reset |  | ||||||
|       int retry = 0; |  | ||||||
|       while (!this->get_status()) { |  | ||||||
|         vTaskDelay(pdMS_TO_TICKS(1000)); |  | ||||||
|         retry++; |  | ||||||
|         if (retry > 10) { |  | ||||||
|           ESP_LOGW(TAG, "Unable to power on modem"); |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|     } else { |  | ||||||
|       ESP_LOGW(TAG, "No power pin defined. Trying to continue"); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (this->flight_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|     ESP_ERROR_CHECK(gpio_set_level(this->flight_pin_, 1));  // need to be high |  | ||||||
|   } else { |  | ||||||
|     ESP_LOGW(TAG, "No flight pin defined. Trying to continue"); |  | ||||||
|   } |  | ||||||
|   if (this->dtr_pin_ != gpio_num_t::GPIO_NUM_NC) { |  | ||||||
|     ESP_ERROR_CHECK(gpio_set_level(this->dtr_pin_, 1)); |  | ||||||
|   } else { |  | ||||||
|     ESP_LOGW(TAG, "No dtr pin defined. Trying to continue"); |  | ||||||
|   } |  | ||||||
|   vTaskDelay(pdMS_TO_TICKS(15000)); |  | ||||||
|   App.feed_wdt(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ModemComponent::powerdown() { |  | ||||||
|   ESP_LOGI(TAG, "Power down modem"); |  | ||||||
|   if (this->get_status()) { |  | ||||||
|     // https://github.com/Xinyuan-LilyGO/T-SIM7600X/blob/master/examples/PowefOffModem/PowefOffModem.ino#L69-L71 |  | ||||||
|     ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 1)); |  | ||||||
|     vTaskDelay(pdMS_TO_TICKS(2600)); |  | ||||||
|     ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 0)); |  | ||||||
|     int retry = 0; |  | ||||||
|     while (this->get_status()) { |  | ||||||
|       vTaskDelay(pdMS_TO_TICKS(1000)); |  | ||||||
|       retry++; |  | ||||||
|       if (retry > 20) { |  | ||||||
|         ESP_LOGW(TAG, "Unable to power down modem"); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } else { |  | ||||||
|     ESP_LOGW(TAG, "modem is already down"); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| }  // namespace modem | }  // namespace modem | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,11 +4,14 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "esphome/components/network/util.h" | #include "esphome/components/network/util.h" | ||||||
|  | #include "esphome/components/binary_sensor/binary_sensor.h" | ||||||
|  | #include "esphome/components/template/binary_sensor/template_binary_sensor.h" | ||||||
|  |  | ||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP_IDF | ||||||
|  |  | ||||||
| using esphome::esp_log_printf_;  // esp_modem will use esphome logger (needed if other components include | // esp_modem will use esphome logger (needed if other components include esphome/core/log.h) | ||||||
|                                  // esphome/core/log.h) | // We need to do this because "cxx_include/esp_modem_api.hpp" is not a pure C++ header, and use logging. | ||||||
|  | using esphome::esp_log_printf_; | ||||||
| #include <cxx_include/esp_modem_api.hpp> | #include <cxx_include/esp_modem_api.hpp> | ||||||
| #include <driver/gpio.h> | #include <driver/gpio.h> | ||||||
| #include <esp_modem_config.h> | #include <esp_modem_config.h> | ||||||
| @@ -39,37 +42,27 @@ class ModemComponent : public Component { | |||||||
|   bool is_connected(); |   bool is_connected(); | ||||||
|   float get_setup_priority() const override; |   float get_setup_priority() const override; | ||||||
|   bool can_proceed() override; |   bool can_proceed() override; | ||||||
|   void on_shutdown() override { powerdown(); } |  | ||||||
|   network::IPAddresses get_ip_addresses(); |   network::IPAddresses get_ip_addresses(); | ||||||
|   std::string get_use_address() const; |   std::string get_use_address() const; | ||||||
|   void set_use_address(const std::string &use_address); |   void set_use_address(const std::string &use_address); | ||||||
|   void poweron(); |  | ||||||
|   void powerdown(); |  | ||||||
|   void set_rx_pin(gpio_num_t rx_pin) { this->rx_pin_ = rx_pin; } |   void set_rx_pin(gpio_num_t rx_pin) { this->rx_pin_ = rx_pin; } | ||||||
|   void set_tx_pin(gpio_num_t tx_pin) { this->tx_pin_ = tx_pin; } |   void set_tx_pin(gpio_num_t tx_pin) { this->tx_pin_ = tx_pin; } | ||||||
|   void set_power_pin(gpio_num_t power_pin) { this->power_pin_ = power_pin; } |  | ||||||
|   void set_flight_pin(gpio_num_t flight_pin) { this->flight_pin_ = flight_pin; } |  | ||||||
|   void set_username(const std::string username) { this->username_ = std::move(username); } |   void set_username(const std::string username) { this->username_ = std::move(username); } | ||||||
|   void set_password(const std::string password) { this->password_ = std::move(password); } |   void set_password(const std::string password) { this->password_ = std::move(password); } | ||||||
|   void set_pin_code(const std::string pin_code) { this->pin_code_ = std::move(pin_code); } |   void set_pin_code(const std::string pin_code) { this->pin_code_ = std::move(pin_code); } | ||||||
|   void set_apn(const std::string apn) { this->apn_ = std::move(apn); } |   void set_apn(const std::string apn) { this->apn_ = std::move(apn); } | ||||||
|   void set_status_pin(gpio_num_t status_pin) { this->status_pin_ = status_pin; } |  | ||||||
|   void set_dtr_pin(gpio_num_t dtr_pin) { this->dtr_pin_ = dtr_pin; } |  | ||||||
|   void set_model(const std::string &model) { |   void set_model(const std::string &model) { | ||||||
|     this->model_ = this->modem_model_map_.count(model) ? modem_model_map_[model] : ModemModel::UNKNOWN; |     this->model_ = this->modem_model_map_.count(model) ? modem_model_map_[model] : ModemModel::UNKNOWN; | ||||||
|   } |   } | ||||||
|  |   void set_ready_bsensor(binary_sensor::BinarySensor *modem_ready) { this->modem_ready_ = modem_ready; } | ||||||
|   void add_init_at_command(const std::string &cmd) { this->init_at_commands_.push_back(cmd); } |   void add_init_at_command(const std::string &cmd) { this->init_at_commands_.push_back(cmd); } | ||||||
|   bool get_status() { return gpio_get_level(this->status_pin_); } |   bool modem_ready() { return this->modem_ready_->state; } | ||||||
|   std::unique_ptr<DCE> dce; |   std::unique_ptr<DCE> dce; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   gpio_num_t rx_pin_ = gpio_num_t::GPIO_NUM_NC; |   gpio_num_t rx_pin_ = gpio_num_t::GPIO_NUM_NC; | ||||||
|   gpio_num_t tx_pin_ = gpio_num_t::GPIO_NUM_NC; |   gpio_num_t tx_pin_ = gpio_num_t::GPIO_NUM_NC; | ||||||
|   gpio_num_t power_pin_ = gpio_num_t::GPIO_NUM_NC; |   binary_sensor::BinarySensor *modem_ready_; | ||||||
|   gpio_num_t flight_pin_ = gpio_num_t::GPIO_NUM_NC; |  | ||||||
|   gpio_num_t status_pin_ = gpio_num_t::GPIO_NUM_NC; |  | ||||||
|   gpio_num_t dtr_pin_ = gpio_num_t::GPIO_NUM_NC; |  | ||||||
|  |  | ||||||
|   std::string pin_code_; |   std::string pin_code_; | ||||||
|   std::string username_; |   std::string username_; | ||||||
|   std::string password_; |   std::string password_; | ||||||
| @@ -94,7 +87,6 @@ class ModemComponent : public Component { | |||||||
|   static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); |   static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); | ||||||
|   void dump_connect_params_(); |   void dump_connect_params_(); | ||||||
|   std::string use_address_; |   std::string use_address_; | ||||||
|   void config_gpio_(); |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user