From 2180ab17d8d90743ee2943e8d1d975e0598502df Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 25 Oct 2022 16:50:34 +0200 Subject: [PATCH] fix(esp-modem): Support AT with callback in C-API Closes https://github.com/espressif/esp-protocols/issues/143 --- .../include/cxx_include/esp_modem_dte.hpp | 4 +- .../esp_modem/include/esp_modem_c_api_types.h | 2 + components/esp_modem/src/esp_modem_c_api.cpp | 50 ++++++++++++------ components/esp_modem/src/esp_modem_dce.cpp | 2 +- components/esp_modem/src/esp_modem_dte.cpp | 51 ++++++++++--------- 5 files changed, 65 insertions(+), 44 deletions(-) diff --git a/components/esp_modem/include/cxx_include/esp_modem_dte.hpp b/components/esp_modem/include/cxx_include/esp_modem_dte.hpp index 902f46fa2..3d592ea02 100644 --- a/components/esp_modem/include/cxx_include/esp_modem_dte.hpp +++ b/components/esp_modem/include/cxx_include/esp_modem_dte.hpp @@ -116,8 +116,8 @@ private: Lock internal_lock{}; /*!< Locks DTE operations */ unique_buffer buffer; /*!< DTE buffer */ std::shared_ptr cmux_term; /*!< Primary terminal for this DTE */ - std::shared_ptr term; /*!< Reference to the primary terminal (mostly for sending commands) */ - std::shared_ptr other_term; /*!< Secondary terminal for this DTE */ + std::shared_ptr primary_term; /*!< Reference to the primary terminal (mostly for sending commands) */ + std::shared_ptr secondary_term; /*!< Secondary terminal for this DTE */ modem_mode mode; /*!< DTE operation mode */ SignalGroup signal; /*!< Event group used to signal request-response operations */ command_result result; /*!< Command result of the currently exectuted command */ diff --git a/components/esp_modem/include/esp_modem_c_api_types.h b/components/esp_modem/include/esp_modem_c_api_types.h index 66591df43..f47e2a064 100644 --- a/components/esp_modem/include/esp_modem_c_api_types.h +++ b/components/esp_modem/include/esp_modem_c_api_types.h @@ -118,6 +118,8 @@ esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce, esp_modem_terminal_error_ */ esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode); +esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t(*got_line_cb)(uint8_t *data, size_t len), uint32_t timeout_ms); + /** * @} */ diff --git a/components/esp_modem/src/esp_modem_c_api.cpp b/components/esp_modem/src/esp_modem_c_api.cpp index c9ebdda2e..fa1bbdbb2 100644 --- a/components/esp_modem/src/esp_modem_c_api.cpp +++ b/components/esp_modem/src/esp_modem_c_api.cpp @@ -94,22 +94,22 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce return ESP_ERR_INVALID_ARG; } switch (mode) { - case ESP_MODEM_MODE_DATA: - return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_COMMAND: - return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_CMUX: - return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_CMUX_MANUAL: - return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_CMUX_MANUAL_EXIT: - return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_EXIT) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_CMUX_MANUAL_SWAP: - return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_SWAP) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_CMUX_MANUAL_DATA: - return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL; - case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND: - return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_DATA: + return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_COMMAND: + return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_CMUX: + return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_CMUX_MANUAL: + return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_CMUX_MANUAL_EXIT: + return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_EXIT) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_CMUX_MANUAL_SWAP: + return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_SWAP) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_CMUX_MANUAL_DATA: + return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL; + case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND: + return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL; } return ESP_ERR_NOT_SUPPORTED; } @@ -400,3 +400,21 @@ extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_mo pdp.protocol_type = c_api_pdp->protocol_type; return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp)); } + +extern "C" esp_err_t esp_modem_command(esp_modem_dce_t *dce_wrap, const char *command, esp_err_t(*got_line_fn)(uint8_t *data, size_t len), uint32_t timeout_ms) +{ + if (dce_wrap == nullptr || dce_wrap->dce == nullptr || command == nullptr || got_line_fn == nullptr) { + return ESP_ERR_INVALID_ARG; + } + std::string cmd(command); + return command_response_to_esp_err(dce_wrap->dce->command(cmd, [got_line_fn](uint8_t *data, size_t len) { + switch (got_line_fn(data, len)) { + case ESP_OK: + return command_result::OK; + case ESP_FAIL: + return command_result::FAIL; + default: + return command_result::TIMEOUT; + } + }, timeout_ms)); +} diff --git a/components/esp_modem/src/esp_modem_dce.cpp b/components/esp_modem/src/esp_modem_dce.cpp index 5cd5895e6..afd41ffa6 100644 --- a/components/esp_modem/src/esp_modem_dce.cpp +++ b/components/esp_modem/src/esp_modem_dce.cpp @@ -130,7 +130,7 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m mode = modem_mode::CMUX_MODE; return transitions::enter_data(*dte, *device, netif); case modem_mode::CMUX_MANUAL_MODE: - if (mode != modem_mode::COMMAND_MODE) { + if (mode != modem_mode::COMMAND_MODE && mode != modem_mode::UNDEF) { return false; } device->set_mode(modem_mode::CMUX_MODE); diff --git a/components/esp_modem/src/esp_modem_dte.cpp b/components/esp_modem/src/esp_modem_dte.cpp index b962b97ad..f8eec5579 100644 --- a/components/esp_modem/src/esp_modem_dte.cpp +++ b/components/esp_modem/src/esp_modem_dte.cpp @@ -15,24 +15,24 @@ using namespace esp_modem; static const size_t dte_default_buffer_size = 1000; DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr terminal): - buffer(config->dte_buffer_size), - cmux_term(nullptr), term(std::move(terminal)), other_term(term), - mode(modem_mode::UNDEF) {} + buffer(config->dte_buffer_size), + cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term), + mode(modem_mode::UNDEF) {} DTE::DTE(std::unique_ptr terminal): - buffer(dte_default_buffer_size), - cmux_term(nullptr), term(std::move(terminal)), other_term(term), - mode(modem_mode::UNDEF) {} + buffer(dte_default_buffer_size), + cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term), + mode(modem_mode::UNDEF) {} command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator) { Scoped l(internal_lock); result = command_result::TIMEOUT; signal.clear(GOT_LINE); - term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) { + primary_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) { if (!data) { data = buffer.get(); - len = term->read(data + buffer.consumed, buffer.size - buffer.consumed); + len = primary_term->read(data + buffer.consumed, buffer.size - buffer.consumed); } else { buffer.consumed = 0; // if the underlying terminal contains data, we cannot fragment } @@ -46,13 +46,13 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui buffer.consumed += len; return false; }); - term->write((uint8_t *)command.c_str(), command.length()); + primary_term->write((uint8_t *)command.c_str(), command.length()); auto got_lf = signal.wait(GOT_LINE, time_ms); if (got_lf && result == command_result::TIMEOUT) { ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE); } buffer.consumed = 0; - term->set_read_cb(nullptr); + primary_term->set_read_cb(nullptr); return result; } @@ -68,26 +68,26 @@ bool DTE::exit_cmux() } auto ejected = cmux_term->detach(); // return the ejected terminal and buffer back to this DTE - term = std::move(ejected.first); + primary_term = std::move(ejected.first); buffer = std::move(ejected.second); - other_term = term; + secondary_term = primary_term; return true; } bool DTE::setup_cmux() { - cmux_term = std::make_shared(term, std::move(buffer)); + cmux_term = std::make_shared(primary_term, std::move(buffer)); if (cmux_term == nullptr) { return false; } if (!cmux_term->init()) { return false; } - term = std::make_unique(cmux_term, 0); - if (term == nullptr) { + primary_term = std::make_unique(cmux_term, 0); + if (primary_term == nullptr) { return false; } - other_term = std::make_unique(cmux_term, 1); + secondary_term = std::make_unique(cmux_term, 1); return true; } @@ -108,7 +108,7 @@ bool DTE::set_mode(modem_mode m) if (m == modem_mode::DATA_MODE) { if (mode == modem_mode::CMUX_MODE || mode == modem_mode::CMUX_MANUAL_MODE) { // mode stays the same, but need to swap terminals (as command has been switched) - other_term.swap(term); + secondary_term.swap(primary_term); } else { mode = m; } @@ -150,19 +150,20 @@ bool DTE::set_mode(modem_mode m) } // manual CMUX transitions: Swap terminals if (m == modem_mode::CMUX_MANUAL_SWAP && mode == modem_mode::CMUX_MANUAL_MODE) { - other_term.swap(term); + secondary_term.swap(primary_term); return true; } - return true; + mode = modem_mode::UNDEF; + return false; } void DTE::set_read_cb(std::function f) { on_data = std::move(f); - other_term->set_read_cb([this](uint8_t *data, size_t len) { + secondary_term->set_read_cb([this](uint8_t *data, size_t len) { if (!data) { // if no data available from terminal callback -> need to explicitly read some data = buffer.get(); - len = other_term->read(buffer.get(), buffer.size); + len = secondary_term->read(buffer.get(), buffer.size); } if (on_data) { return on_data(data, len); @@ -173,22 +174,22 @@ void DTE::set_read_cb(std::function f) void DTE::set_error_cb(std::function f) { - other_term->set_error_cb(f); - term->set_error_cb(f); + secondary_term->set_error_cb(f); + primary_term->set_error_cb(f); } int DTE::read(uint8_t **d, size_t len) { auto data_to_read = std::min(len, buffer.size); auto data = buffer.get(); - auto actual_len = other_term->read(data, data_to_read); + auto actual_len = secondary_term->read(data, data_to_read); *d = data; return actual_len; } int DTE::write(uint8_t *data, size_t len) { - return other_term->write(data, len); + return secondary_term->write(data, len); } /**