diff --git a/components/esp_modem/src/esp_modem_command_library.cpp b/components/esp_modem/src/esp_modem_command_library.cpp index 9d69bbe809..0d8a8b1299 100644 --- a/components/esp_modem/src/esp_modem_command_library.cpp +++ b/components/esp_modem/src/esp_modem_command_library.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -89,10 +89,9 @@ template command_result generic_get_string(CommandableIf *t, const std::string_view response((char *)data, len); while ((pos = response.find('\n')) != std::string::npos) { std::string_view token = response.substr(0, pos); - for (auto it = token.end() - 1; it > token.begin(); it--) // strip trailing CR or LF - if (*it == '\r' || *it == '\n') { - token.remove_suffix(1); - } + while (!token.empty() && (token.back() == '\r' || token.back() == '\n')) { + token.remove_suffix(1); + } ESP_LOGV(TAG, "Token: {%.*s}\n", static_cast(token.size()), token.data()); if (token.find("OK") != std::string::npos) { @@ -187,7 +186,7 @@ command_result get_battery_status(CommandableIf *t, int &voltage, int &bcs, int out = out.substr(pattern.size()); int pos, value, property = 0; while ((pos = out.find(',')) != std::string::npos) { - if (std::from_chars(out.data(), out.data() + pos, value).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data(), out.data() + pos, value).ec != std::errc{}) { return command_result::FAIL; } switch (property++) { @@ -200,7 +199,7 @@ command_result get_battery_status(CommandableIf *t, int &voltage, int &bcs, int } out = out.substr(pos + 1); } - if (std::from_chars(out.data(), out.data() + out.size(), voltage).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data(), out.data() + out.size(), voltage).ec != std::errc{}) { return command_result::FAIL; } return command_result::OK; @@ -224,10 +223,13 @@ command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &b } int volt, fraction; - if (std::from_chars(out.data() + num_pos, out.data() + dot_pos, volt).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + num_pos, out.data() + dot_pos, volt).ec != std::errc{}) { + return command_result::FAIL; + } + if (dot_pos + 2 > out.size()) { return command_result::FAIL; } - if (std::from_chars(out.data() + dot_pos + 1, out.data() + out.size() - 1, fraction).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + dot_pos + 1, out.data() + out.size() - 1, fraction).ec != std::errc{}) { return command_result::FAIL; } bcl = bcs = -1; // not available for these models @@ -256,14 +258,14 @@ command_result get_operator_name(CommandableIf *t, std::string &operator_name, i if (property++ == 2) { // operator name is after second comma (as a 3rd property of COPS string) operator_name = out.substr(++pos); auto additional_comma = operator_name.find(','); // check for the optional ACT - if (additional_comma != std::string::npos && std::from_chars(operator_name.data() + additional_comma + 1, operator_name.data() + operator_name.length(), act).ec != std::errc::invalid_argument) { + if (additional_comma != std::string::npos && std::from_chars(operator_name.data() + additional_comma + 1, operator_name.data() + operator_name.length(), act).ec == std::errc{}) { operator_name = operator_name.substr(0, additional_comma); } // and strip quotes if present auto quote1 = operator_name.find('"'); auto quote2 = operator_name.rfind('"'); - if (quote1 != std::string::npos && quote2 != std::string::npos) { - operator_name = operator_name.substr(quote1 + 1, quote2 - 1); + if (quote1 != std::string::npos && quote2 != std::string::npos && quote2 > quote1) { + operator_name = operator_name.substr(quote1 + 1, quote2 - quote1 - 1); } return command_result::OK; } @@ -447,10 +449,10 @@ command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber) return command_result::FAIL; } - if (std::from_chars(out.data() + rssi_pos, out.data() + ber_pos, rssi).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + rssi_pos, out.data() + ber_pos, rssi).ec != std::errc{}) { return command_result::FAIL; } - if (std::from_chars(out.data() + ber_pos + 1, out.data() + out.size(), ber).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + ber_pos + 1, out.data() + out.size(), ber).ec != std::errc{}) { return command_result::FAIL; } return command_result::OK; @@ -482,7 +484,7 @@ command_result get_network_attachment_state(CommandableIf *t, int &state) return command_result::FAIL; } - if (std::from_chars(out.data() + pos, out.data() + out.size(), state).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + pos, out.data() + out.size(), state).ec != std::errc{}) { return command_result::FAIL; } @@ -509,7 +511,7 @@ command_result get_radio_state(CommandableIf *t, int &state) return command_result::FAIL; } - if (std::from_chars(out.data() + pos, out.data() + out.size(), state).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + pos, out.data() + out.size(), state).ec != std::errc{}) { return command_result::FAIL; } @@ -570,12 +572,16 @@ command_result get_network_system_mode(CommandableIf *t, int &mode) } constexpr std::string_view pattern = "+CNSMOD: "; - int mode_pos = out.find(",") + 1; // Skip "," if (out.find(pattern) == std::string::npos) { return command_result::FAIL; } + auto comma = out.find(','); + if (comma == std::string::npos) { + return command_result::FAIL; + } + size_t mode_pos = comma + 1; - if (std::from_chars(out.data() + mode_pos, out.data() + out.size(), mode).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + mode_pos, out.data() + out.size(), mode).ec != std::errc{}) { return command_result::FAIL; } @@ -602,7 +608,7 @@ command_result get_gnss_power_mode(CommandableIf *t, int &mode) return command_result::FAIL; } - if (std::from_chars(out.data() + pos, out.data() + out.size(), mode).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + pos, out.data() + out.size(), mode).ec != std::errc{}) { return command_result::FAIL; } @@ -668,7 +674,7 @@ command_result get_network_registration_state(CommandableIf *t, int &state) } // Extract state value (skip the comma) - if (std::from_chars(out.data() + state_pos_start + 1, out.data() + state_pos_end, state).ec == std::errc::invalid_argument) { + if (std::from_chars(out.data() + state_pos_start + 1, out.data() + state_pos_end, state).ec != std::errc{}) { return command_result::FAIL; } diff --git a/components/esp_modem/src/esp_modem_dte.cpp b/components/esp_modem/src/esp_modem_dte.cpp index 9c6fdd14e5..8ebb5d2dd5 100644 --- a/components/esp_modem/src/esp_modem_dte.cpp +++ b/components/esp_modem/src/esp_modem_dte.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -166,6 +166,7 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui #ifdef CONFIG_ESP_MODEM_URC_HANDLER // Track command end buffer_state.command_waiting = false; + buffer_state.last_urc_processed = 0; #endif buffer.consumed = 0; #ifdef CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED @@ -398,6 +399,11 @@ bool DTE::command_cb::process_line(uint8_t *data, size_t consumed, size_t len, D case UrcConsumeResult::CONSUME_PARTIAL: // Consume only specified amount + if (consume_info.consume_size > consumed + len) { + ESP_LOGW("esp_modem_dte", "URC consume_size %zu exceeds buffer %zu, treating as CONSUME_NONE", + (size_t)consume_info.consume_size, (size_t)(consumed + len)); + break; + } dte->buffer_state.last_urc_processed += consume_info.consume_size; // Adjust data pointers for command processing data += consume_info.consume_size; diff --git a/components/esp_modem/src/esp_modem_netif.cpp b/components/esp_modem/src/esp_modem_netif.cpp index 1220853fcb..c8513e8740 100644 --- a/components/esp_modem/src/esp_modem_netif.cpp +++ b/components/esp_modem/src/esp_modem_netif.cpp @@ -120,6 +120,7 @@ void Netif::pause() Netif::~Netif() { + ppp_dte->set_read_cb(nullptr); if (signal.is_any(PPP_STARTED)) { esp_netif_action_stop(driver.base.netif, nullptr, 0, nullptr); signal.clear(PPP_STARTED);