/* softAP to PPPoS Example (modem_board) This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include "cxx_include/esp_modem_dte.hpp" #include "esp_modem_config.h" #include "cxx_include/esp_modem_api.hpp" #include "cxx_include/esp_modem_dce_factory.hpp" #include #include using namespace esp_modem; using namespace esp_modem::dce_factory; class NetModule; typedef DCE_T NetDCE; /** * @brief Local network object used to setup PPP network */ class PPPNetwork { public: esp_err_t init(esp_netif_t *netif, const std::string& apn, const std::string &pin_number); NetDCE * get_dce(); private: NetDCE *dce; }; /** * @brief The PPP network is a singleton, allocate statically here */ static PPPNetwork ppp_network; /** * @brief Custom factory for creating NetDCE and NetModule */ class NetDCE_Factory: public Factory { public: template static DCE_T* create(const config *cfg, Args&&... args) { return build_generic_DCE(cfg, std::forward(args)...); } template static std::shared_ptr create_module(const config *cfg, Args&&... args) { return build_shared_module(cfg, std::forward(args)...); } }; /** * @brief This is an example of implementing minimal network module functionality * * This does only include those AT commands, that are needed for setting the network up * and also initialization part (set pin, ...) */ class NetModule: public ModuleIf { public: explicit NetModule(std::shared_ptr dte, const esp_modem_dce_config *cfg): dte(std::move(dte)), apn(std::string(cfg->apn)) {} bool setup_data_mode() override { PdpContext pdp(apn); if (set_pdp_context(pdp) != command_result::OK) return false; return true; } bool set_mode(modem_mode mode) override { if (mode == modem_mode::DATA_MODE) { if (set_data_mode() != command_result::OK) return resume_data_mode() == command_result::OK; return true; } if (mode == modem_mode::COMMAND_MODE) { return set_command_mode() == command_result::OK; } return false; } bool init(const std::string& pin) { // switch to command mode (in case we were in PPP mode) static_cast(set_command_mode()); // ignore the potential failure, as we might be in command mode after startup bool is_pin_ok; if (read_pin(is_pin_ok) != command_result::OK) return false; if (!is_pin_ok) { if (set_pin(pin) != command_result::OK) return false; vTaskDelay(pdMS_TO_TICKS(1000)); if (read_pin(is_pin_ok) != command_result::OK || !is_pin_ok) return false; } return true; } private: std::shared_ptr dte; std::string apn; [[nodiscard]] command_result set_pdp_context(PdpContext& pdp) { return dce_commands::set_pdp_context(dte.get(),pdp); } [[nodiscard]] command_result set_pin(const std::string &pin) { return dce_commands::set_pin(dte.get(), pin); } [[nodiscard]] command_result read_pin(bool& pin_ok) { return dce_commands::read_pin(dte.get(), pin_ok); } [[nodiscard]] command_result set_data_mode() { return dce_commands::set_data_mode(dte.get()); } [[nodiscard]] command_result resume_data_mode() { return dce_commands::resume_data_mode(dte.get()); } [[nodiscard]] command_result set_command_mode() { return dce_commands::set_command_mode(dte.get()); } }; esp_err_t PPPNetwork::init(esp_netif_t *netif, const std::string& apn, const std::string &pin_number) { // configure esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); dte_config.uart_config.event_task_stack_size = 4096; dte_config.uart_config.rx_buffer_size = 16384; dte_config.uart_config.tx_buffer_size = 2048; esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(apn.c_str()); // create DTE and minimal network DCE auto uart_dte = create_uart_dte(&dte_config); // create the specific device (and initialize it) auto dev = NetDCE_Factory::create_module(&dce_config, uart_dte, netif); if (!dev->init(pin_number)) return ESP_FAIL; // now create the DCE from our already existent device dce = NetDCE_Factory::create(&dce_config, uart_dte, netif, dev); if (dce == nullptr) return ESP_FAIL; return ESP_OK; } NetDCE *PPPNetwork::get_dce() { return dce; } extern "C" esp_err_t modem_init_network(esp_netif_t *netif) { return ppp_network.init(netif, "internet", "1234"); } extern "C" void modem_start_network() { ppp_network.get_dce()->set_mode(esp_modem::modem_mode::DATA_MODE); } extern "C" void modem_stop_network() { ppp_network.get_dce()->set_mode(esp_modem::modem_mode::COMMAND_MODE); }