mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 01:34:18 +01:00
recover from alternate cmux state
This commit is contained in:
parent
e4d6f5e58d
commit
4e6da9f34d
2 changed files with 123 additions and 42 deletions
|
@ -54,7 +54,12 @@ void ModemComponent::dump_config() { this->dump_connect_params_(); }
|
|||
|
||||
float ModemComponent::get_setup_priority() const { return setup_priority::WIFI + 1; } // just before WIFI
|
||||
|
||||
bool ModemComponent::can_proceed() { return this->is_connected(); }
|
||||
bool ModemComponent::can_proceed() {
|
||||
if (!this->enabled_) {
|
||||
return true;
|
||||
}
|
||||
return this->is_connected();
|
||||
}
|
||||
|
||||
network::IPAddresses ModemComponent::get_ip_addresses() {
|
||||
network::IPAddresses addresses;
|
||||
|
@ -81,6 +86,10 @@ void ModemComponent::setup() {
|
|||
|
||||
if (this->power_pin_) {
|
||||
this->power_pin_->setup();
|
||||
|
||||
if (this->enabled_) {
|
||||
this->poweron_();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->status_pin_) {
|
||||
|
@ -127,16 +136,16 @@ void ModemComponent::setup() {
|
|||
nullptr);
|
||||
ESPHL_ERROR_CHECK(err, "IP event handler register error");
|
||||
|
||||
this->create_dte_dce_();
|
||||
// if (!this->power_transition_) {
|
||||
// this->create_dte_dce_();
|
||||
// }
|
||||
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
|
||||
if (this->enabled_ && !this->get_power_status()) {
|
||||
ESP_LOGI(TAG, "Powering up modem");
|
||||
|
||||
this->poweron_();
|
||||
}
|
||||
App.feed_wdt();
|
||||
// if (this->enabled_ && !this->get_power_status()) {
|
||||
// ESP_LOGI(TAG, "Powering up modem");
|
||||
//
|
||||
// this->poweron_();
|
||||
//}
|
||||
// App.feed_wdt();
|
||||
ESP_LOGV(TAG, "Setup finished");
|
||||
}
|
||||
|
||||
|
@ -160,6 +169,10 @@ void ModemComponent::create_dte_dce_() {
|
|||
|
||||
this->dte_ = create_uart_dte(&dte_config);
|
||||
|
||||
if (this->dte_->set_mode(modem_mode::COMMAND_MODE)) {
|
||||
ESP_LOGD(TAG, "dte in command mode");
|
||||
}
|
||||
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(this->apn_.c_str());
|
||||
|
||||
#if defined(USE_MODEM_MODEL_GENERIC)
|
||||
|
@ -185,24 +198,51 @@ void ModemComponent::create_dte_dce_() {
|
|||
// ESP_LOGD(TAG, "set_flow_control OK");
|
||||
// }
|
||||
|
||||
// Try to exit CMUX_MANUAL_DATA or DATA_MODE, if any
|
||||
// No error check done. It can take some times if the commands fail
|
||||
// but this allow to recover from a previous session.
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
if (this->cmux_) {
|
||||
this->dce->set_mode(modem_mode::CMUX_MANUAL_MODE);
|
||||
this->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND);
|
||||
} else if (!this->modem_ready()) {
|
||||
this->dce->set_mode(modem_mode::COMMAND_MODE);
|
||||
}
|
||||
if (this->enabled_) {
|
||||
if (!this->watchdog_)
|
||||
this->watchdog_ = std::make_shared<watchdog::WatchdogManager>(60000);
|
||||
|
||||
// App.feed_wdt();
|
||||
if (this->modem_ready()) {
|
||||
ESP_LOGD(TAG, "modem ready after exiting cmux/data mode");
|
||||
} else {
|
||||
// the modem may be off. As the status pin is optionnal (and seems to be unreliable)
|
||||
// we can be sure of the cause.
|
||||
ESP_LOGD(TAG, "modem *not* ready after exiting cmux/data mode");
|
||||
// check modem is ready after dte and dce init.
|
||||
if (!this->modem_ready()) {
|
||||
// Try to exit CMUX_MANUAL_DATA or DATA_MODE, if any
|
||||
ESP_LOGD(TAG, "Connecting to the the modem...");
|
||||
|
||||
uint32_t start_ms = millis();
|
||||
std::string result;
|
||||
|
||||
auto command_mode_ = [this]() -> bool {
|
||||
ESP_LOGVV(TAG, "trying command mode");
|
||||
this->dce->set_mode(modem_mode::UNDEF);
|
||||
return this->dce->set_mode(modem_mode::COMMAND_MODE) && this->modem_ready();
|
||||
};
|
||||
|
||||
auto cmux_command_mode_ = [this]() -> bool {
|
||||
ESP_LOGVV(TAG, "trying cmux command mode");
|
||||
return this->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) &&
|
||||
this->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) && this->modem_ready();
|
||||
};
|
||||
|
||||
// The cmux state is supposed to be the same before the reboot. But if it has changed (new firwmare), we will try
|
||||
// to fallback to inverted cmux state.
|
||||
bool status;
|
||||
if (this->cmux_) {
|
||||
status = cmux_command_mode_() || (command_mode_() && cmux_command_mode_());
|
||||
} else {
|
||||
status = command_mode_() || (cmux_command_mode_() && command_mode_());
|
||||
}
|
||||
|
||||
uint32_t elapsed_ms = millis() - start_ms;
|
||||
|
||||
if (!status) {
|
||||
ESP_LOGW(TAG, "modem not responding after %" PRIu32 "ms");
|
||||
if (this->power_pin_) {
|
||||
ESP_LOGD(TAG, "Trying to power cycle the modem");
|
||||
this->poweroff_();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Connected to the modem in %" PRIu32 "ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGV(TAG, "DTE and CDE created");
|
||||
}
|
||||
|
@ -238,7 +278,6 @@ bool ModemComponent::prepare_sim_() {
|
|||
|
||||
void ModemComponent::send_init_at_() {
|
||||
// send initial AT commands from yaml
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
for (const auto &cmd : this->init_at_commands_) {
|
||||
std::string result = this->send_at(cmd);
|
||||
if (result == "ERROR") {
|
||||
|
@ -250,14 +289,17 @@ void ModemComponent::send_init_at_() {
|
|||
}
|
||||
}
|
||||
|
||||
void ModemComponent::start_connect_() {
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
bool ModemComponent::start_connect_() {
|
||||
this->connect_begin_ = millis();
|
||||
this->status_set_warning("Starting connection");
|
||||
|
||||
// will be set to true on event IP_EVENT_PPP_GOT_IP
|
||||
this->got_ipv4_address_ = false;
|
||||
|
||||
// esp_event_post(IP_EVENT, IP_EVENT_PPP_LOST_IP, nullptr, 0, 0);
|
||||
|
||||
this->dump_dce_status_();
|
||||
|
||||
if (this->cmux_) {
|
||||
ESP_LOGD(TAG, "Entering CMUX mode");
|
||||
this->dce->set_mode(modem_mode::CMUX_MANUAL_MODE);
|
||||
|
@ -266,7 +308,13 @@ void ModemComponent::start_connect_() {
|
|||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Unable to enter CMUX mode");
|
||||
this->status_set_error("Unable to enter CMUX mode");
|
||||
// if (this->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND)) {
|
||||
// ESP_LOGD(TAG, "Switched to command mode");
|
||||
// }
|
||||
this->poweroff_();
|
||||
return false;
|
||||
// ESPMODEM_ERROR_CHECK(this->dce->hang_up(), "Unable to hang up modem. Trying to continue anyway.");
|
||||
// this->status_set_error("Unable to enter CMUX mode");
|
||||
}
|
||||
assert(this->modem_ready());
|
||||
} else {
|
||||
|
@ -276,9 +324,12 @@ void ModemComponent::start_connect_() {
|
|||
} else {
|
||||
ESP_LOGE(TAG, "Unable to enter DATA mode");
|
||||
this->status_set_error("Unable to enter DATA mode");
|
||||
this->poweroff_();
|
||||
return false;
|
||||
}
|
||||
assert(!this->modem_ready());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModemComponent::ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
|
||||
|
@ -314,7 +365,6 @@ void ModemComponent::loop() {
|
|||
switch (this->state_) {
|
||||
case ModemComponentState::NOT_RESPONDING:
|
||||
if (this->start_) {
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
if (this->modem_ready()) {
|
||||
ESP_LOGI(TAG, "Modem recovered");
|
||||
this->status_clear_warning();
|
||||
|
@ -339,13 +389,14 @@ void ModemComponent::loop() {
|
|||
case ModemComponentState::DISCONNECTED:
|
||||
if (this->enabled_) {
|
||||
if (this->start_) {
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
if (this->modem_ready()) {
|
||||
this->send_init_at_();
|
||||
if (this->prepare_sim_()) {
|
||||
ESP_LOGI(TAG, "Starting modem connection");
|
||||
this->state_ = ModemComponentState::CONNECTING;
|
||||
this->start_connect_();
|
||||
if (this->start_connect_()) {
|
||||
this->state_ = ModemComponentState::CONNECTING;
|
||||
}
|
||||
|
||||
} else {
|
||||
this->disable();
|
||||
}
|
||||
|
@ -359,6 +410,7 @@ void ModemComponent::loop() {
|
|||
}
|
||||
} else {
|
||||
this->state_ = ModemComponentState::DISABLED;
|
||||
this->watchdog_.reset();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -372,10 +424,16 @@ void ModemComponent::loop() {
|
|||
|
||||
this->dump_connect_params_();
|
||||
this->status_clear_warning();
|
||||
this->watchdog_.reset();
|
||||
|
||||
} else if (now - this->connect_begin_ > 45000) {
|
||||
ESP_LOGW(TAG, "Connecting via Modem failed! Re-connecting...");
|
||||
this->state_ = ModemComponentState::DISCONNECTED;
|
||||
} else {
|
||||
// ESP_LOGD(TAG, "Connecting...");
|
||||
App.feed_wdt();
|
||||
App.get_app_state();
|
||||
// yield();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -391,7 +449,7 @@ void ModemComponent::loop() {
|
|||
case ModemComponentState::DISCONNECTING:
|
||||
if (this->start_) {
|
||||
if (this->connected_) {
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
// watchdog::WatchdogManager wdt(60000);
|
||||
ESP_LOGD(TAG, "Going to hang up...");
|
||||
this->dump_connect_params_();
|
||||
if (this->cmux_) {
|
||||
|
@ -487,15 +545,17 @@ void ModemComponent::poweron_() {
|
|||
// use a timout for long wait delay
|
||||
ESP_LOGD(TAG, "Will check that the modem is on in %.1fs...", float(USE_MODEM_POWER_TONUART) / 1000);
|
||||
this->set_timeout("wait_poweron", USE_MODEM_POWER_TONUART, [this]() {
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
ESP_LOGD(TAG, "DTE/DCE init after poweron");
|
||||
this->create_dte_dce_();
|
||||
delay(500); // NOLINT
|
||||
App.feed_wdt();
|
||||
if (!this->modem_ready()) {
|
||||
ESP_LOGE(TAG, "Unable to power on the modem");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Modem ready after power ON");
|
||||
}
|
||||
this->power_transition_ = false;
|
||||
yield();
|
||||
});
|
||||
}
|
||||
#else
|
||||
|
@ -511,9 +571,10 @@ void ModemComponent::poweroff_() {
|
|||
#ifdef USE_MODEM_POWER
|
||||
if (this->power_pin_) {
|
||||
ESP_LOGV(TAG, "Powering off modem with power pin...");
|
||||
App.feed_wdt();
|
||||
this->power_transition_ = true;
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
this->power_pin_->digital_write(true);
|
||||
// watchdog::WatchdogManager wdt(60000);
|
||||
// this->power_pin_->digital_write(true);
|
||||
delay(10);
|
||||
this->power_pin_->digital_write(false);
|
||||
delay(USE_MODEM_POWER_TOFF);
|
||||
|
@ -521,8 +582,6 @@ void ModemComponent::poweroff_() {
|
|||
|
||||
ESP_LOGD(TAG, "Will check that the modem is off in %.1fs...", float(USE_MODEM_POWER_TOFFUART) / 1000);
|
||||
this->set_timeout("wait_poweroff", USE_MODEM_POWER_TOFFUART, [this]() {
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
|
||||
if (this->modem_ready()) {
|
||||
ESP_LOGE(TAG, "Unable to power off the modem");
|
||||
} else {
|
||||
|
@ -557,6 +616,25 @@ void ModemComponent::dump_connect_params_() {
|
|||
ESP_LOGCONFIG(TAG, " DNS fallback: %s", network::IPAddress(dns_fallback_ip).str().c_str());
|
||||
}
|
||||
|
||||
void ModemComponent::dump_dce_status_() {
|
||||
ESP_LOGCONFIG(TAG, "Modem status:");
|
||||
int network_attachment_state;
|
||||
std::string result;
|
||||
command_result err = this->dce->get_network_attachment_state(network_attachment_state);
|
||||
if (err == command_result::OK) {
|
||||
result = network_attachment_state ? "Yes" : "No";
|
||||
} else {
|
||||
result = "command " + command_result_to_string(err);
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Attached to network: %s", result.c_str());
|
||||
|
||||
this->dce->get_module_name(result);
|
||||
if (err != command_result::OK) {
|
||||
result = "command " + command_result_to_string(err);
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Module name : %s", result.c_str());
|
||||
}
|
||||
|
||||
std::string ModemComponent::send_at(const std::string &cmd) {
|
||||
std::string result;
|
||||
command_result status;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "esphome/core/gpio.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/components/watchdog/watchdog.h"
|
||||
|
||||
// esp_modem will use esphome logger (needed if other components include 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.
|
||||
|
@ -75,11 +76,12 @@ class ModemComponent : public Component {
|
|||
void create_dte_dce_(); // (re)create dte and dce
|
||||
bool prepare_sim_();
|
||||
void send_init_at_();
|
||||
void start_connect_();
|
||||
bool start_connect_();
|
||||
void poweron_();
|
||||
void poweroff_();
|
||||
static void ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||
void dump_connect_params_();
|
||||
void dump_dce_status_();
|
||||
InternalGPIOPin *tx_pin_;
|
||||
InternalGPIOPin *rx_pin_;
|
||||
GPIOPin *status_pin_{nullptr};
|
||||
|
@ -97,6 +99,7 @@ class ModemComponent : public Component {
|
|||
std::shared_ptr<DTE> dte_{nullptr};
|
||||
esp_netif_t *ppp_netif_{nullptr};
|
||||
ModemComponentState state_{ModemComponentState::DISABLED};
|
||||
std::shared_ptr<watchdog::WatchdogManager> watchdog_;
|
||||
bool cmux_{false};
|
||||
bool start_{false};
|
||||
bool enabled_{false};
|
||||
|
|
Loading…
Reference in a new issue