diff --git a/esp_modem/CMakeLists.txt b/esp_modem/CMakeLists.txt index 91148ae9c..58e4c7908 100644 --- a/esp_modem/CMakeLists.txt +++ b/esp_modem/CMakeLists.txt @@ -10,7 +10,12 @@ set(srcs "src/esp_modem.c" "src/esp_bg96.c" "src/esp_modem_dte.cpp" "src/ppp_netif.cpp" - "src/esp_modem_commands.cpp") + "src/esp_modem_commands.cpp" + "src/esp_modem_api.cpp" + "src/esp_modem_dce.cpp" + "src/esp_modem_device.cpp" + "src/esp_modem_device_factory.cpp" + "src/esp_modem_uart.cpp") set(include_dirs "include") diff --git a/esp_modem/examples/simple_cxx_client/main/simple_client.cpp b/esp_modem/examples/simple_cxx_client/main/simple_client.cpp index cb9abec4a..fa198375b 100644 --- a/esp_modem/examples/simple_cxx_client/main/simple_client.cpp +++ b/esp_modem/examples/simple_cxx_client/main/simple_client.cpp @@ -17,8 +17,9 @@ #include "esp_log.h" #include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/uart_terminal.hpp" +#include "cxx_include/esp_modem_api.hpp" -#define BROKER_URL "mqtt://mqtt.eclipse.org" +#define BROKER_URL "mqtt://mqtt.eclipseprojects.io" static const char *TAG = "pppos_example"; static EventGroupHandle_t event_group = NULL; @@ -135,9 +136,11 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_ int msg_id; switch (event->event_id) { case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0); - ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + ESP_LOGE(TAG, "MQTT_EVENT_CONNECTED"); + xEventGroupSetBits(event_group, GOT_DATA_BIT); +// +// msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0); +// ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); @@ -262,36 +265,58 @@ static void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_con // dte_config->line_buffer_size = 1000000; uint8_t data[32] = {}; int actual_len = 0; - auto ddd = create_dte(dte_config); - ddd->set_mode(dte_mode::UNDEF); - ddd->send_command("AT+CPIN?\r", [&](uint8_t *data, size_t len) { + auto uart_dte = create_uart_dte(dte_config); + uart_dte->set_mode(dte_mode::UNDEF); + uart_dte->command("+++", [&](uint8_t *data, size_t len) { std::string response((char*)data, len); ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); std::cout << response << std::endl; - return true; + return command_result::OK; }, 1000); -// ddd->send_command("AT+CPIN=1234\r", [&](uint8_t *data, size_t len) { +// uart_dte->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) { // std::string response((char*)data, len); // ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); // std::cout << response << std::endl; -// return true; +// return command_result::OK; // }, 1000); +// uart_dte->command("AT+CPIN=1234\r", [&](uint8_t *data, size_t len) { +// std::string response((char*)data, len); +// ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); +// std::cout << response << std::endl; +// return command_result::OK; +// }, 1000); +// // return; esp_netif_t *esp_netif = esp_netif_new(ppp_config); assert(esp_netif); - auto my_dce = create_dce(ddd, esp_netif); + std::string apn = "internet"; + auto device = create_device(uart_dte, apn); + auto my_dce = create_dce(uart_dte, device, esp_netif); my_dce->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) { std::string response((char*)data, len); ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); std::cout << response << std::endl; - return true; + return command_result::OK; }, 1000); my_dce->set_data(); + /* Config MQTT */ + xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY); + esp_mqtt_client_config_t mqtt_config = { }; + mqtt_config.uri = BROKER_URL; + esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config); + esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, mqtt_event_handler, NULL); + esp_mqtt_client_start(mqtt_client); + xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY); + esp_mqtt_client_destroy(mqtt_client); + +// vTaskDelay(pdMS_TO_TICKS(20000)); + my_dce->exit_data(); + // ddd->send_command("AT+COPS=?\r", [&](uint8_t *data, size_t len) { // std::string response((char*)data, len); // ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); @@ -312,6 +337,13 @@ static void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_con // vTaskDelay(pdMS_TO_TICKS(1000)); // len = uart->read(data, 32); ESP_LOGI(TAG, "len=%d data %s", actual_len, (char*)data); + + uart_dte->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) { + std::string response((char*)data, len); + ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); + std::cout << response << std::endl; + return command_result::OK; + }, 1000); return; /* create dce object */ diff --git a/esp_modem/include/cxx_include/esp_modem_api.hpp b/esp_modem/include/cxx_include/esp_modem_api.hpp new file mode 100644 index 000000000..b6c5dd24d --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_api.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include "cxx_include/esp_modem_dce.hpp" +#include "cxx_include/esp_modem_device_factory.hpp" + +class DTE; +struct dte_config; +typedef struct esp_netif_obj esp_netif_t; + +std::shared_ptr create_uart_dte(const dte_config *config); + +std::unique_ptr create_dce(const std::shared_ptr& dte, const std::shared_ptr& dev, esp_netif_t *netif); + diff --git a/esp_modem/include/cxx_include/esp_modem_commands.hpp b/esp_modem/include/cxx_include/esp_modem_commands.hpp index 90ce6ce7a..9bef58c3a 100644 --- a/esp_modem/include/cxx_include/esp_modem_commands.hpp +++ b/esp_modem/include/cxx_include/esp_modem_commands.hpp @@ -5,12 +5,81 @@ #ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_COMMANDS_HPP #define SIMPLE_CXX_CLIENT_ESP_MODEM_COMMANDS_HPP -#include "esp_err.h" +#include "esp_modem_dte.hpp" +//#include "esp_modem_dce_commands.hpp" +enum class command_result; +struct PdpContext { + PdpContext(std::string& apn): context_id(1), protocol_type("IP"), apn(apn) {} + size_t context_id; + std::string protocol_type; + std::string apn; +}; + + +#include namespace esp_modem { namespace dce_commands { -template esp_err_t sync(T t); +template static inline command_result generic_command(T t, const std::string& command, + const std::string& pass_phrase, + const std::string& fail_phrase, uint32_t timeout_ms) +{ + std::cout << command << std::endl; + return t->command(command.c_str(), [&](uint8_t *data, size_t len) { + std::string response((char*)data, len); + std::cout << response << std::endl; + + if (response.find(pass_phrase) != std::string::npos) { + return command_result::OK; + } else if (response.find(fail_phrase) != std::string::npos) { + return command_result::FAIL; + } + return command_result::TIMEOUT; + }, timeout_ms); +} + +template static inline command_result generic_command_common(T t, std::string command) +{ + return generic_command(t, command, "OK", "ERROR", 500); +} + + +template command_result sync(T t) +{ + return generic_command_common(t, "AT\r"); +} + +template command_result set_echo(T t, bool on) +{ + if (on) + return generic_command_common(t, "ATE1\r"); + return generic_command_common(t, "ATE0\r"); +} + +template command_result set_pdp_context(T t, PdpContext& pdp) +{ + std::string pdp_command = "AT+CGDCONT=" + std::to_string(pdp.context_id) + + ",\"" + pdp.protocol_type + "\",\"" + pdp.apn + "\"\r"; + return generic_command_common(t, pdp_command); +} + +template command_result set_data_mode(T t) +{ + return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000); +} + +template command_result resume_data_mode(T t) +{ + return generic_command(t, "ATO\r", "CONNECT", "ERROR", 5000); +} + +template command_result set_command_mode(T t) +{ + return generic_command(t, "+++", "OK", "ERROR", 50000); +} + + } // dce_commands } // esp_modem diff --git a/esp_modem/include/cxx_include/esp_modem_dce.hpp b/esp_modem/include/cxx_include/esp_modem_dce.hpp new file mode 100644 index 000000000..e2fb16109 --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_dce.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "cxx_include/esp_modem_dce_commands_if.hpp" + +class DCE { +public: + explicit DCE(const std::shared_ptr& d, std::shared_ptr device, esp_netif_t * netif); + void set_data() { +// command("AT+CGDCONT=1,\"IP\",\"internet\"\r", [&](uint8_t *data, size_t len) { +// return command_result::OK; +// }, 1000); +// command("ATD*99***1#\r", [&](uint8_t *data, size_t len) { +// return command_result::OK; +// }, 1000); + device->setup_data_mode(); + device->set_mode(dte_mode::DATA_MODE); + dce_dte->set_mode(dte_mode::DATA_MODE); + ppp_netif.start(); + } + void exit_data() { + ppp_netif.stop(); + device->set_mode(dte_mode::COMMAND_MODE); + ppp_netif.wait_until_ppp_exits(); + dce_dte->set_mode(dte_mode::COMMAND_MODE); + } + command_result command(const std::string& command, got_line_cb got_line, uint32_t time_ms) { + return dce_dte->command(command, got_line, time_ms); + } +private: + std::shared_ptr dce_dte; + std::shared_ptr device; + ppp ppp_netif; +}; \ No newline at end of file diff --git a/esp_modem/include/cxx_include/esp_modem_dce_commands.hpp b/esp_modem/include/cxx_include/esp_modem_dce_commands.hpp new file mode 100644 index 000000000..4fdc59b23 --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_dce_commands.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "cxx_include/esp_modem_dce_commands_if.hpp" +#include "cxx_include/esp_modem_commands.hpp" +#include +#include + +enum class command_result; +class DTE; + +class Device: public DeviceIf { +public: + explicit Device(std::shared_ptr dte, std::unique_ptr pdp): + dte(std::move(dte)), pdp(std::move(pdp)) {} + bool setup_data_mode() override; + bool set_mode(dte_mode mode) override; + + command_result set_echo(bool on) { return esp_modem::dce_commands::set_echo(dte, on); } + command_result set_data_mode() { return esp_modem::dce_commands::set_data_mode(dte); } + command_result resume_data_mode() { return esp_modem::dce_commands::resume_data_mode(dte); } + command_result set_pdp_context(PdpContext& pdp_context) { return esp_modem::dce_commands::set_pdp_context(dte.get(), pdp_context); } + command_result set_command_mode() { return esp_modem::dce_commands::set_command_mode(dte); } + +private: + std::shared_ptr dte; + std::unique_ptr pdp; +}; + + diff --git a/esp_modem/include/cxx_include/esp_modem_dce_commands_if.hpp b/esp_modem/include/cxx_include/esp_modem_dce_commands_if.hpp new file mode 100644 index 000000000..b2d5d0841 --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_dce_commands_if.hpp @@ -0,0 +1,9 @@ +#pragma once + +enum class dte_mode; + +class DeviceIf { +public: + virtual bool setup_data_mode() = 0; + virtual bool set_mode(dte_mode mode) = 0; +}; \ No newline at end of file diff --git a/esp_modem/include/cxx_include/esp_modem_device_factory.hpp b/esp_modem/include/cxx_include/esp_modem_device_factory.hpp new file mode 100644 index 000000000..240565e6c --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_device_factory.hpp @@ -0,0 +1,3 @@ +#pragma once + +std::shared_ptr create_device(const std::shared_ptr& dte, std::string &apn); \ No newline at end of file diff --git a/esp_modem/include/cxx_include/esp_modem_dte.hpp b/esp_modem/include/cxx_include/esp_modem_dte.hpp index fd1d2c170..6c20b1aeb 100644 --- a/esp_modem/include/cxx_include/esp_modem_dte.hpp +++ b/esp_modem/include/cxx_include/esp_modem_dte.hpp @@ -51,19 +51,21 @@ enum class dte_mode { DATA_MODE }; -const int DTE_BUFFER_SIZE = 1024; - -struct dte_data { - uint8_t *data; - size_t len; +enum class command_result { + OK, + FAIL, + TIMEOUT }; -typedef std::function got_line_cb; +const int DTE_BUFFER_SIZE = 1024; -class dte { + +typedef std::function got_line_cb; + +class DTE { public: - explicit dte(std::unique_ptr t); - ~dte() = default; + explicit DTE(std::unique_ptr t); + ~DTE() = default; // void set_line_cb(got_line f) { on_line_cb = std::move(f); } int write(uint8_t *data, size_t len) { return term->write(data, len); } int read(uint8_t **d, size_t len) { @@ -83,7 +85,7 @@ public: term->set_data_cb(on_data); } } - bool send_command(const std::string& command, got_line_cb got_line, uint32_t time_ms); + command_result command(const std::string& command, got_line_cb got_line, uint32_t time_ms); private: const size_t GOT_LINE = BIT0; @@ -98,27 +100,7 @@ private: }; -class dce { -public: - explicit dce(std::shared_ptr d, esp_netif_t * netif); - void set_data() { - command("AT+CGDCONT=1,\"IP\",\"internet\"\r", [&](uint8_t *data, size_t len) { - return true; - }, 1000); - command("ATD*99***1#\r", [&](uint8_t *data, size_t len) { - return true; - }, 1000); - dce_dte->set_mode(dte_mode::DATA_MODE); - ppp_netif.start(); - } - bool command(const std::string& command, got_line_cb got_line, uint32_t time_ms) { - return dce_dte->send_command(command, got_line, time_ms); - } -private: - std::shared_ptr dce_dte; - ppp ppp_netif; -}; diff --git a/esp_modem/include/cxx_include/esp_modem_uart_terminal.hpp b/esp_modem/include/cxx_include/esp_modem_uart_terminal.hpp new file mode 100644 index 000000000..84c4c7b3a --- /dev/null +++ b/esp_modem/include/cxx_include/esp_modem_uart_terminal.hpp @@ -0,0 +1,10 @@ +// +// Created by david on 3/3/21. +// + +#ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_UART_TERMINAL_HPP +#define SIMPLE_CXX_CLIENT_ESP_MODEM_UART_TERMINAL_HPP + + + +#endif //SIMPLE_CXX_CLIENT_ESP_MODEM_UART_TERMINAL_HPP diff --git a/esp_modem/include/cxx_include/ppp_netif.hpp b/esp_modem/include/cxx_include/ppp_netif.hpp index 31efe87d7..33ec34e70 100644 --- a/esp_modem/include/cxx_include/ppp_netif.hpp +++ b/esp_modem/include/cxx_include/ppp_netif.hpp @@ -6,26 +6,33 @@ #define SIMPLE_CXX_CLIENT_PPP_NETIF_HPP #include "esp_netif.h" +#include "cxx_include/terminal_objects.hpp" -class dte; +class DTE; //struct ppp_netif_driver; struct ppp_netif_driver { esp_netif_driver_base_t base; - dte *e; + DTE *e; }; class ppp { public: - explicit ppp(std::shared_ptr e, esp_netif_t *netif); + explicit ppp(std::shared_ptr e, esp_netif_t *netif); void start(); + void notify_ppp_exit() { signal.set(PPP_EXIT); } + void wait_until_ppp_exits() { signal.wait(PPP_EXIT, 50000); } + void stop(); private: void receive(uint8_t *data, size_t len) const; - std::shared_ptr ppp_dte; + std::shared_ptr ppp_dte; esp_netif_t *netif; struct ppp_netif_driver driver; + signal_group signal; + const size_t PPP_EXIT = BIT0; + }; diff --git a/esp_modem/include/cxx_include/uart_terminal.hpp b/esp_modem/include/cxx_include/uart_terminal.hpp index ef7d769b0..67749cec7 100644 --- a/esp_modem/include/cxx_include/uart_terminal.hpp +++ b/esp_modem/include/cxx_include/uart_terminal.hpp @@ -6,15 +6,12 @@ #define SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP #include "cxx_include/esp_modem_dte.hpp" -#include "esp_modem_dte_config.h" -std::unique_ptr create_uart_terminal(const struct dte_config *config); -class dte; +struct dte_config; -std::shared_ptr create_dte(const struct dte_config *config); +std::unique_ptr create_uart_terminal(const dte_config *config); -std::unique_ptr create_dce(const std::shared_ptr& e, esp_netif_t *netif); #endif //SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP diff --git a/esp_modem/src/esp_modem_api.cpp b/esp_modem/src/esp_modem_api.cpp new file mode 100644 index 000000000..29edb6a64 --- /dev/null +++ b/esp_modem/src/esp_modem_api.cpp @@ -0,0 +1,44 @@ +// +// Created by david on 3/3/21. +// +#include "cxx_include/esp_modem_dte.hpp" +#include "cxx_include/uart_terminal.hpp" +#include "esp_log.h" +#include "cxx_include/esp_modem_api.hpp" + +static const char *TAG = "dce_factory"; +struct PdpContext; + +std::shared_ptr create_uart_dte(const dte_config *config) +{ + try { +// auto term = std::make_unique(std::make_unique(config)); + auto term = create_uart_terminal(config); + return std::make_shared(std::move(term)); + } catch (std::bad_alloc& e) { + ESP_LOGE(TAG, "Out of memory"); + return nullptr; + } catch (esp_err_exception& e) { + esp_err_t err = e.get_err_t(); + ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); + ESP_LOGE(TAG, "%s", e.what()); + return nullptr; + } + +} + +std::unique_ptr create_dce(const std::shared_ptr& dte, const std::shared_ptr& dev, esp_netif_t *netif) +{ + try { + return std::make_unique(dte, dev, netif); + } catch (std::bad_alloc& e) { + ESP_LOGE(TAG, "Out of memory"); + return nullptr; + } catch (esp_err_exception& e) { + esp_err_t err = e.get_err_t(); + ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); + ESP_LOGE(TAG, "%s", e.what()); + return nullptr; + } +} + diff --git a/esp_modem/src/esp_modem_commands.cpp b/esp_modem/src/esp_modem_commands.cpp index 4b959267e..95d118bbf 100644 --- a/esp_modem/src/esp_modem_commands.cpp +++ b/esp_modem/src/esp_modem_commands.cpp @@ -5,18 +5,61 @@ namespace esp_modem::dce_commands { -template esp_err_t sync(T t) -{ - return t->send_command("AT\r", [&](uint8_t *data, size_t len) { - std::string response((char*)data, len); - if (response.find("OK") != std::string::npos) { - return ESP_OK; - } else if (response.find("ERROR") != std::string::npos) { - return ESP_FAIL; - } - return ESP_ERR_INVALID_STATE; - }, 1000); -} + + +//template static inline command_result generic_command(T t, std::string command, +// std::string pass_phrase, std::string fail_phrase, uint32_t timeout_ms) +//{ +// return t->command(command.c_str(), [&](uint8_t *data, size_t len) { +// std::string response((char*)data, len); +// if (response.find(pass_phrase) != std::string::npos) { +// return command_result::OK; +// } else if (response.find(fail_phrase) != std::string::npos) { +// return command_result::FAIL; +// } +// return command_result::TIMEOUT; +// }, timeout_ms); +//} +// +//template static inline command_result generic_command_common(T t, std::string command) +//{ +// return generic_command(t, command, "OK", "ERROR", 500); +//} +// + +//template command_result sync(T t) +//{ +// return t->command("AT\r", [&](uint8_t *data, size_t len) { +// std::string response((char*)data, len); +// if (response.find("OK") != std::string::npos) { +// return command_result::OK; +// } else if (response.find("ERROR") != std::string::npos) { +// return command_result::FAIL; +// } +// return command_result::TIMEOUT; +// }, 1000); +//} + +//template command_result set_echo(T t, bool on) { return command_result::OK; } + + + +//template command_result set_echo(T* t, bool on) +//{ +// if (on) +// return generic_command_common(t, "ATE1\r"); +// return generic_command_common(t, "ATE0\r"); +//} +// +//template command_result set_data_mode(T t) +//{ +// return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000); +//} +// +//template command_result set_pdp_context(T t, PdpContext& pdp_context) +//{ +// return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000); +//} } @@ -25,7 +68,7 @@ namespace esp_modem { template class generic_dce { public: - explicit generic_dce(std::shared_ptr e) : dce_dte(std::move(e)) {} + explicit generic_dce(std::shared_ptr e) : dce_dte(std::move(e)) {} esp_err_t sync() { return dce_commands::sync(dce_dte); } diff --git a/esp_modem/src/esp_modem_dce.cpp b/esp_modem/src/esp_modem_dce.cpp new file mode 100644 index 000000000..db5dc94ca --- /dev/null +++ b/esp_modem/src/esp_modem_dce.cpp @@ -0,0 +1,11 @@ +#include "cxx_include/esp_modem_dte.hpp" +#include "cxx_include/esp_modem_dce.hpp" +#include + +#include +#include "esp_log.h" + +DCE::DCE(const std::shared_ptr& dte, std::shared_ptr device, esp_netif_t * netif): + dce_dte(dte), device(std::move(device)), ppp_netif(dte, netif) +{ } + diff --git a/esp_modem/src/esp_modem_device.cpp b/esp_modem/src/esp_modem_device.cpp new file mode 100644 index 000000000..c1d86ff8c --- /dev/null +++ b/esp_modem/src/esp_modem_device.cpp @@ -0,0 +1,30 @@ +// +// Created by david on 3/3/21. +// + +#include "cxx_include/esp_modem_dce_commands.hpp" +#include "cxx_include/esp_modem_dte.hpp" + + + +bool Device::setup_data_mode() { + if (set_echo(false) != command_result::OK) + return false; + if (set_pdp_context(*pdp) != command_result::OK) + return false; +// if (set_data_mode() != command_result::OK) +// return false; + return true; +} + +bool Device::set_mode(dte_mode mode) { + if (mode == dte_mode::DATA_MODE) { + if (set_data_mode() != command_result::OK) + return resume_data_mode() == command_result::OK; + return true; + } else if (mode == dte_mode::COMMAND_MODE) { + return set_command_mode() == command_result::OK; + } + return true; +} + diff --git a/esp_modem/src/esp_modem_device_factory.cpp b/esp_modem/src/esp_modem_device_factory.cpp new file mode 100644 index 000000000..5e16a5edd --- /dev/null +++ b/esp_modem/src/esp_modem_device_factory.cpp @@ -0,0 +1,9 @@ +#include "cxx_include/esp_modem_dce_commands.hpp" +#include "cxx_include/esp_modem_dte.hpp" + +std::shared_ptr create_device(const std::shared_ptr& dte, std::string &apn) +{ + auto pdp = std::make_unique(apn); + return std::make_shared(dte, std::move(pdp)); +} + diff --git a/esp_modem/src/esp_modem_dte.cpp b/esp_modem/src/esp_modem_dte.cpp index 4904c26f4..44675e753 100644 --- a/esp_modem/src/esp_modem_dte.cpp +++ b/esp_modem/src/esp_modem_dte.cpp @@ -1,334 +1,16 @@ -// -// Created by david on 2/24/21. -// - #include "cxx_include/esp_modem_dte.hpp" -#include #include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "esp_modem.h" -#include "esp_modem_dce.h" #include "esp_log.h" -#include "sdkconfig.h" -#include "esp_modem_internal.h" -#include "esp_modem_dte_internal.h" -#include "esp_modem_dte_config.h" -#include -#include -#define ESP_MODEM_EVENT_QUEUE_SIZE (16) -#define MIN_PATTERN_INTERVAL (9) -#define MIN_POST_IDLE (0) -#define MIN_PRE_IDLE (0) +DTE::DTE(std::unique_ptr terminal): + buffer_size(DTE_BUFFER_SIZE), consumed(0), + buffer(std::make_unique(buffer_size)), + term(std::move(terminal)), mode(dte_mode::UNDEF) {} -static const char *TAG = "dte_uart"; - -//class uart_terminal; - -//class dte { -//public: -// esp_err_t init(std::unique_ptr t); -// -//private: -// std::unique_ptr m_terminal; -// -//}; - -struct uart_task { - explicit uart_task(size_t stack_size, size_t priority, void* task_param, TaskFunction_t task_function): - task_handle(nullptr) - { - BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle); - throw_if_false(ret == pdTRUE, "create uart event task failed"); - } - ~uart_task() - { - if (task_handle) vTaskDelete(task_handle); - } - - TaskHandle_t task_handle; /*!< UART event task handle */ -}; - - - -struct uart_event_loop { - explicit uart_event_loop(): event_loop_hdl(nullptr) - { - esp_event_loop_args_t loop_args = {}; - loop_args.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE; - loop_args.task_name = nullptr; - throw_if_esp_fail(esp_event_loop_create(&loop_args, &event_loop_hdl), "create event loop failed"); - } - void run() { esp_event_loop_run(event_loop_hdl, pdMS_TO_TICKS(0)); } - - ~uart_event_loop() { if (event_loop_hdl) esp_event_loop_delete(event_loop_hdl); } - - esp_event_loop_handle_t event_loop_hdl; -}; - -struct uart_resource { - explicit uart_resource(const struct dte_config *config); - - ~uart_resource(); - - bool get_event(uart_event_t& event, uint32_t time_ms) - { - return xQueueReceive(event_queue, &event, pdMS_TO_TICKS(time_ms)); - } - void reset_events() - { - uart_flush_input(port); - xQueueReset(event_queue); - } - - uart_port_t port; /*!< UART port */ - QueueHandle_t event_queue; /*!< UART event queue handle */ -// esp_modem_on_receive receive_cb; /*!< ptr to data reception */ -// void *receive_cb_ctx; /*!< ptr to rx fn context data */ - int line_buffer_size; /*!< line buffer size in command mode */ - int pattern_queue_size; /*!< UART pattern queue size */ -}; - -class uart_terminal: public terminal { -public: - explicit uart_terminal(const struct dte_config *config): - uart(config), event_loop(), signal(), - task_handle(config->event_task_stack_size, config->event_task_priority, this, s_task) {} - - ~uart_terminal() override = default; - void start() override - { - signal.set(TASK_START); - } - void stop() override - { - signal.set(TASK_STOP); - } -// { ESP_LOGE(TAG, "uart_terminal destruct"); } - - int write(uint8_t *data, size_t len) override; - int read(uint8_t *data, size_t len) override; - -private: - static void s_task(void * task_param) - { - auto t = static_cast(task_param); - t->task(); - vTaskDelete(NULL); - } - void task(); - - const size_t TASK_INIT = BIT0; - const size_t TASK_START = BIT1; - const size_t TASK_STOP = BIT2; - - - uart_resource uart; - uart_event_loop event_loop; - signal_group signal; - uart_task task_handle; - -}; - - -uart_resource::~uart_resource() -{ - if (port >= UART_NUM_0 && port < UART_NUM_MAX) { - uart_driver_delete(port); - } -} - - - - -uart_resource::uart_resource(const struct dte_config *config): - port(-1) -// buffer(std::make_unique(config->line_buffer_size)) -{ - esp_err_t res; - - line_buffer_size = config->line_buffer_size; - - /* TODO: Bind methods */ - - /* Config UART */ - uart_config_t uart_config = {}; - uart_config.baud_rate = config->baud_rate; - uart_config.data_bits = config->data_bits; - uart_config.parity = config->parity; - uart_config.stop_bits = config->stop_bits; - uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS - : UART_HW_FLOWCTRL_DISABLE; - uart_config.source_clk = UART_SCLK_REF_TICK; - - throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed"); - - if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) { - res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num, - config->rts_io_num, config->cts_io_num); - } else { - res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num, - UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - } - throw_if_esp_fail(res, "config uart gpio failed"); - /* Set flow control threshold */ - if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) { - res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8); - } else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) { - res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8); - } - throw_if_esp_fail(res, "config uart flow control failed"); - /* Install UART driver and get event queue used inside driver */ - res = uart_driver_install(config->port_num, config->rx_buffer_size, config->tx_buffer_size, - config->event_queue_size, &(event_queue), 0); - throw_if_esp_fail(res, "install uart driver failed"); - throw_if_esp_fail(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed"); - - /* Set pattern interrupt, used to detect the end of a line. */ -// res = uart_enable_pattern_det_baud_intr(config->port_num, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE); - /* Set pattern queue size */ -// pattern_queue_size = config->pattern_queue_size; -// res |= uart_pattern_queue_reset(config->port_num, config->pattern_queue_size); - /* Starting in command mode -> explicitly disable RX interrupt */ -// uart_disable_rx_intr(config->port_num); - uart_set_rx_full_threshold(config->port_num, 64); - throw_if_esp_fail(res, "config uart pattern failed"); - /* mark UART as initialized */ - port = config->port_num; -} - -std::unique_ptr create_uart_terminal(const struct dte_config *config) -{ - try { - auto term = std::make_unique(config); - term->start(); - return term; - } catch (std::bad_alloc& e) { - ESP_LOGE(TAG, "Out of memory"); - return nullptr; - } catch (esp_err_exception& e) { - esp_err_t err = e.get_err_t(); - ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); - ESP_LOGE(TAG, "%s", e.what()); - return nullptr; - } - -} - -std::shared_ptr create_dte(const struct dte_config *config) -{ - try { -// auto term = std::make_unique(std::make_unique(config)); - auto term = std::make_shared(std::make_unique(config)); - return term; - } catch (std::bad_alloc& e) { - ESP_LOGE(TAG, "Out of memory"); - return nullptr; - } catch (esp_err_exception& e) { - esp_err_t err = e.get_err_t(); - ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); - ESP_LOGE(TAG, "%s", e.what()); - return nullptr; - } - -} - -std::unique_ptr create_dce(const std::shared_ptr& e, esp_netif_t *netif) -{ - try { - return std::make_unique(e, netif); - } catch (std::bad_alloc& e) { - ESP_LOGE(TAG, "Out of memory"); - return nullptr; - } catch (esp_err_exception& e) { - esp_err_t err = e.get_err_t(); - ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); - ESP_LOGE(TAG, "%s", e.what()); - return nullptr; - } -} - - -void uart_terminal::task() -{ - uart_event_t event; - size_t len; - signal.set(TASK_INIT); - signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY); - if (signal.is_any(TASK_STOP)) { - return; // deletes the static task - } - while(signal.is_any(TASK_START)) { - event_loop.run(); - if (uart.get_event(event, 100)) { - switch (event.type) { - case UART_DATA: - ESP_LOGI(TAG, "UART_DATA"); - uart_get_buffered_data_len(uart.port, &len); - ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data); - if (len && on_data) { - on_data(len); - } - break; - case UART_FIFO_OVF: - ESP_LOGW(TAG, "HW FIFO Overflow"); - uart.reset_events(); - break; - case UART_BUFFER_FULL: - ESP_LOGW(TAG, "Ring Buffer Full"); - uart.reset_events(); - break; - case UART_BREAK: - ESP_LOGW(TAG, "Rx Break"); - break; - case UART_PARITY_ERR: - ESP_LOGE(TAG, "Parity Error"); - break; - case UART_FRAME_ERR: - ESP_LOGE(TAG, "Frame Error"); - break; - case UART_PATTERN_DET: - ESP_LOGI(TAG, "UART_PATTERN_DET"); - break; - default: - ESP_LOGW(TAG, "unknown uart event type: %d", event.type); - break; - } - } - -// ESP_LOGI(TAG, "uart_event_task_entry"); -// vTaskDelay(pdMS_TO_TICKS(200)); - - } -} - -int uart_terminal::read(uint8_t *data, size_t len) -{ - size_t length = 0; - uart_get_buffered_data_len(uart.port, &length); - if (length > 0) { - return uart_read_bytes(uart.port, data, length, portMAX_DELAY); - } - return 0; -} - -int uart_terminal::write(uint8_t *data, size_t len) -{ - return uart_write_bytes(uart.port, data, len); -} - -dte::dte(std::unique_ptr terminal): - buffer_size(DTE_BUFFER_SIZE), consumed(0), - buffer(std::make_unique(buffer_size)), - term(std::move(terminal)), mode(dte_mode::UNDEF) {} - - -bool dte::send_command(const std::string& command, got_line_cb got_line, uint32_t time_ms) +command_result DTE::command(const std::string& command, got_line_cb got_line, uint32_t time_ms) { + command_result res = command_result::TIMEOUT; term->write((uint8_t *)command.c_str(), command.length()); term->set_data_cb([&](size_t len){ auto data_to_read = std::min(len, buffer_size - consumed); @@ -336,18 +18,17 @@ bool dte::send_command(const std::string& command, got_line_cb got_line, uint32_ auto actual_len = term->read(data, data_to_read); consumed += actual_len; if (memchr(data, '\n', actual_len)) { - ESP_LOGD("in the lambda", "FOUND"); - if (got_line(buffer.get(), consumed)) { + res = got_line(buffer.get(), consumed); + if (res == command_result::OK || res == command_result::FAIL) { signal.set(GOT_LINE); } } }); - auto res = signal.wait(GOT_LINE, time_ms); + auto got_lf = signal.wait(GOT_LINE, time_ms); + if (got_lf && res == command_result::TIMEOUT) { + throw_if_esp_fail(ESP_ERR_INVALID_STATE); + } consumed = 0; + term->set_data_cb(nullptr); return res; -} - -dce::dce(std::shared_ptr e, esp_netif_t * netif): -dce_dte(e), ppp_netif(e, netif) -{ } - +} \ No newline at end of file diff --git a/esp_modem/src/esp_modem_uart.cpp b/esp_modem/src/esp_modem_uart.cpp new file mode 100644 index 000000000..50feae7ea --- /dev/null +++ b/esp_modem/src/esp_modem_uart.cpp @@ -0,0 +1,246 @@ + +#include "cxx_include/esp_modem_dte.hpp" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_log.h" +#include "esp_event.h" +#include "driver/uart.h" +#include "esp_modem_dte_config.h" + +#define ESP_MODEM_EVENT_QUEUE_SIZE (16) + +static const char *TAG = "uart_terminal"; + +struct uart_resource { + explicit uart_resource(const struct dte_config *config); + + ~uart_resource(); + + bool get_event(uart_event_t& event, uint32_t time_ms) + { + return xQueueReceive(event_queue, &event, pdMS_TO_TICKS(time_ms)); + } + void reset_events() + { + uart_flush_input(port); + xQueueReset(event_queue); + } + + uart_port_t port; /*!< UART port */ + QueueHandle_t event_queue; /*!< UART event queue handle */ + int line_buffer_size; /*!< line buffer size in command mode */ + int pattern_queue_size; /*!< UART pattern queue size */ +}; + +struct uart_task { + explicit uart_task(size_t stack_size, size_t priority, void* task_param, TaskFunction_t task_function): + task_handle(nullptr) + { + BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle); + throw_if_false(ret == pdTRUE, "create uart event task failed"); + } + ~uart_task() + { + if (task_handle) vTaskDelete(task_handle); + } + + TaskHandle_t task_handle; /*!< UART event task handle */ +}; + + +struct uart_event_loop { + explicit uart_event_loop(): event_loop_hdl(nullptr) + { + esp_event_loop_args_t loop_args = {}; + loop_args.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE; + loop_args.task_name = nullptr; + throw_if_esp_fail(esp_event_loop_create(&loop_args, &event_loop_hdl), "create event loop failed"); + } + void run() { esp_event_loop_run(event_loop_hdl, pdMS_TO_TICKS(0)); } + + ~uart_event_loop() { if (event_loop_hdl) esp_event_loop_delete(event_loop_hdl); } + + esp_event_loop_handle_t event_loop_hdl; +}; + +uart_resource::~uart_resource() +{ + if (port >= UART_NUM_0 && port < UART_NUM_MAX) { + uart_driver_delete(port); + } +} + + +uart_resource::uart_resource(const struct dte_config *config): + port(-1) +{ + esp_err_t res; + line_buffer_size = config->line_buffer_size; + + /* Config UART */ + uart_config_t uart_config = {}; + uart_config.baud_rate = config->baud_rate; + uart_config.data_bits = config->data_bits; + uart_config.parity = config->parity; + uart_config.stop_bits = config->stop_bits; + uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS + : UART_HW_FLOWCTRL_DISABLE; + uart_config.source_clk = UART_SCLK_REF_TICK; + + throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed"); + + if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) { + res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num, + config->rts_io_num, config->cts_io_num); + } else { + res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num, + UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + throw_if_esp_fail(res, "config uart gpio failed"); + /* Set flow control threshold */ + if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) { + res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8); + } else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) { + res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8); + } + throw_if_esp_fail(res, "config uart flow control failed"); + /* Install UART driver and get event queue used inside driver */ + res = uart_driver_install(config->port_num, config->rx_buffer_size, config->tx_buffer_size, + config->event_queue_size, &(event_queue), 0); + throw_if_esp_fail(res, "install uart driver failed"); + throw_if_esp_fail(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed"); + + uart_set_rx_full_threshold(config->port_num, 64); + throw_if_esp_fail(res, "config uart pattern failed"); + /* mark UART as initialized */ + port = config->port_num; +} + +class uart_terminal: public terminal { +public: + explicit uart_terminal(const struct dte_config *config): + uart(config), event_loop(), signal(), + task_handle(config->event_task_stack_size, config->event_task_priority, this, s_task) {} + + ~uart_terminal() override = default; + void start() override + { + signal.set(TASK_START); + } + void stop() override + { + signal.set(TASK_STOP); + } + + int write(uint8_t *data, size_t len) override; + int read(uint8_t *data, size_t len) override; + +private: + static void s_task(void * task_param) + { + auto t = static_cast(task_param); + t->task(); + vTaskDelete(NULL); + } + void task(); + + const size_t TASK_INIT = BIT0; + const size_t TASK_START = BIT1; + const size_t TASK_STOP = BIT2; + + + uart_resource uart; + uart_event_loop event_loop; + signal_group signal; + uart_task task_handle; + +}; + +std::unique_ptr create_uart_terminal(const dte_config *config) +{ + try { + auto term = std::make_unique(config); + term->start(); + return term; + } catch (std::bad_alloc& e) { + ESP_LOGE(TAG, "Out of memory"); + return nullptr; + } catch (esp_err_exception& e) { + esp_err_t err = e.get_err_t(); + ESP_LOGE(TAG, "Error occurred during UART term init: %d", err); + ESP_LOGE(TAG, "%s", e.what()); + return nullptr; + } + +} + + + +void uart_terminal::task() +{ + uart_event_t event; + size_t len; + signal.set(TASK_INIT); + signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY); + if (signal.is_any(TASK_STOP)) { + return; // exits to the static method where the task gets deleted + } + while(signal.is_any(TASK_START)) { + event_loop.run(); + if (uart.get_event(event, 100)) { + switch (event.type) { + case UART_DATA: + ESP_LOGI(TAG, "UART_DATA"); +// ESP_LOG_BUFFER_HEXDUMP("esp-modem-pattern: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG); + uart_get_buffered_data_len(uart.port, &len); + ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data); + if (len && on_data) { + on_data(len); + } + break; + case UART_FIFO_OVF: + ESP_LOGW(TAG, "HW FIFO Overflow"); + uart.reset_events(); + break; + case UART_BUFFER_FULL: + ESP_LOGW(TAG, "Ring Buffer Full"); + uart.reset_events(); + break; + case UART_BREAK: + ESP_LOGW(TAG, "Rx Break"); + break; + case UART_PARITY_ERR: + ESP_LOGE(TAG, "Parity Error"); + break; + case UART_FRAME_ERR: + ESP_LOGE(TAG, "Frame Error"); + break; + case UART_PATTERN_DET: + ESP_LOGI(TAG, "UART_PATTERN_DET"); + break; + default: + ESP_LOGW(TAG, "unknown uart event type: %d", event.type); + break; + } + } + } +} + +int uart_terminal::read(uint8_t *data, size_t len) +{ + size_t length = 0; + uart_get_buffered_data_len(uart.port, &length); + if (length > 0) { + return uart_read_bytes(uart.port, data, length, portMAX_DELAY); + } + return 0; +} + +int uart_terminal::write(uint8_t *data, size_t len) +{ + return uart_write_bytes(uart.port, data, len); +} + + + diff --git a/esp_modem/src/ppp_netif.cpp b/esp_modem/src/ppp_netif.cpp index c9270be4c..6ea1dc1b6 100644 --- a/esp_modem/src/ppp_netif.cpp +++ b/esp_modem/src/ppp_netif.cpp @@ -9,6 +9,7 @@ #include "cxx_include/esp_modem_dte.hpp" #include "esp_netif_ppp.h" +#include //struct ppp_netif_driver { // esp_netif_driver_base_t base; @@ -17,19 +18,23 @@ static void on_ppp_changed(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { - dte *e = (dte*)arg; + ppp *e = (ppp*)arg; +// DTE *e = (DTE*)arg; + std::cout << "on_ppp_changed " << std::endl; ESP_LOGW("TAG", "PPP state changed event %d", event_id); if (event_id < NETIF_PP_PHASE_OFFSET) { ESP_LOGI("TAG", "PPP state changed event %d", event_id); // only notify the modem on state/error events, ignoring phase transitions - e->data_mode_closed(); + e->notify_ppp_exit(); +// e->data_mode_closed(); // esp_modem_notify_ppp_netif_closed(dte); } } static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len) { - dte *e = (dte*)h; + DTE *e = (DTE*)h; + std::cout << "sending data " << len << std::endl; if (e->write((uint8_t*)buffer, len) > 0) { return ESP_OK; } @@ -42,28 +47,30 @@ static esp_err_t esp_modem_post_attach(esp_netif_t * esp_netif, void * args) esp_netif_driver_ifconfig_t driver_ifconfig = { }; driver_ifconfig.transmit = esp_modem_dte_transmit; driver_ifconfig.handle = (void*)d->e; - + std::cout << "esp_modem_post_attach " << std::endl; d->base.netif = esp_netif; ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig)); // check if PPP error events are enabled, if not, do enable the error occurred/state changed // to notify the modem layer when switching modes esp_netif_ppp_config_t ppp_config; esp_netif_ppp_get_params(esp_netif, &ppp_config); - if (!ppp_config.ppp_error_event_enabled) { +// if (!ppp_config.ppp_error_event_enabled) { ppp_config.ppp_error_event_enabled = true; + ppp_config.ppp_phase_event_enabled = true; esp_netif_ppp_set_params(esp_netif, &ppp_config); - } +// } - ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void*)d->e)); +// ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, 0)); return ESP_OK; } void ppp::receive(uint8_t *data, size_t len) const { + std::cout << "received data " << len << std::endl; esp_netif_receive(driver.base.netif, data, len, nullptr); } -ppp::ppp(std::shared_ptr e, esp_netif_t *ppp_netif): +ppp::ppp(std::shared_ptr e, esp_netif_t *ppp_netif): ppp_dte(std::move(e)), netif(ppp_netif) { driver.base.netif = ppp_netif; @@ -74,10 +81,20 @@ ppp::ppp(std::shared_ptr e, esp_netif_t *ppp_netif): auto actual_len = ppp_dte->read(&data, len); return receive(data, actual_len); }); + throw_if_esp_fail(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void*)this)); + throw_if_esp_fail(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_netif)); + throw_if_esp_fail(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected, ppp_netif)); throw_if_esp_fail(esp_netif_attach(ppp_netif, &driver)); } void ppp::start() { esp_netif_action_start(driver.base.netif, 0, 0, 0); +} + +void ppp::stop() +{ + std::cout << "esp_netif_action_stop " << std::endl; + esp_netif_action_stop(driver.base.netif, nullptr, 0, nullptr); + } \ No newline at end of file