Skip to content

[modem]: tcp-client example to support multiple connections #849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
set(module_dir "generic_module")
if (CONFIG_EXAMPLE_MODEM_DEVICE_BG96)
set(device_srcs sock_commands_bg96.cpp)
elseif(CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600)
set(device_srcs sock_commands_sim7600.cpp)
elseif(CONFIG_EXAMPLE_MODEM_DEVICE_ESPAT)
set(device_srcs sock_commands_espat.cpp)
set(module_dir "espat_module")
endif()

if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
Expand All @@ -14,4 +18,4 @@ idf_component_register(SRCS "modem_client.cpp"
"${command_dir}/sock_dce.cpp"
"tcp_transport_at.cpp"
"${device_srcs}"
INCLUDE_DIRS "." "${command_dir}")
INCLUDE_DIRS "." "${command_dir}" "${module_dir}")
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,26 @@ menu "Example Configuration"
bool "SIM7600"
help
SIM7600 is Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module
config EXAMPLE_MODEM_DEVICE_ESPAT
bool "ESP-AT"
help
ESP-AT firmware for ESP32 modules with WiFi connectivity
endchoice

if EXAMPLE_MODEM_DEVICE_ESPAT
config EXAMPLE_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) to connect to.

config EXAMPLE_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2).
endif

config EXAMPLE_MODEM_APN
string "Set MODEM APN"
default "internet"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <charconv>
#include <sys/socket.h>
#include <algorithm> // for std::find
#include "esp_vfs.h"
#include "esp_vfs_eventfd.h"

Expand All @@ -15,6 +16,25 @@ namespace sock_dce {

constexpr auto const *TAG = "sock_dce";

// Definition of the static member variables
std::vector<DCE*> DCE::dce_list{};
bool DCE::network_init = false;

// Constructor - add this DCE instance to the static list
DCE::DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config)
: Module(std::move(dte_arg), config)
{
dce_list.push_back(this);
}

// Destructor - remove this DCE instance from the static list
DCE::~DCE()
{
auto it = std::find(dce_list.begin(), dce_list.end(), this);
if (it != dce_list.end()) {
dce_list.erase(it);
}
}

bool DCE::perform_sock()
{
Expand Down Expand Up @@ -104,6 +124,7 @@ void DCE::close_sock()
close(sock);
sock = -1;
}
close(data_ready_fd);
dte->on_read(nullptr);
const int retries = 5;
int i = 0;
Expand Down Expand Up @@ -224,15 +245,18 @@ void DCE::start_listening(int port)

bool DCE::connect(std::string host, int port)
{
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
assert(data_ready_fd > 0);
dte->on_read(nullptr);
tcp_close();
dte->on_read([this](uint8_t *data, size_t len) {
this->perform_at(data, len);
read_callback(data, len);
return esp_modem::command_result::TIMEOUT;
});
if (!at.start_connecting(host, port)) {
ESP_LOGE(TAG, "Unable to start connecting");
dte->on_read(nullptr);
close(data_ready_fd);
return false;
}
state = status::CONNECTING;
Expand All @@ -241,12 +265,13 @@ bool DCE::connect(std::string host, int port)

bool DCE::init()
{
if (network_init) {
return true;
}
network_init = true;
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
esp_vfs_eventfd_register(&config);

data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
assert(data_ready_fd > 0);

dte->on_read(nullptr);
const int retries = 5;
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "cxx_include/esp_modem_api.hpp"
#include <cxx_include/esp_modem_dce_factory.hpp>
#include "sock_commands.hpp"
#include "sock_module.hpp"
#include <sys/socket.h>

#pragma once
Expand Down Expand Up @@ -97,9 +98,15 @@ class Responder {
std::shared_ptr<esp_modem::DTE> &dte;
};

class DCE : public ::esp_modem::GenericModule {
using esp_modem::GenericModule::GenericModule;
class DCE : public Module {
public:
// Constructor and destructor for managing dce_list
// explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
// dte(std::move(dte)), pdp(std::move(pdp)) {}
// explicit GenericModule(std::shared_ptr<DTE> dte, );
//
DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config);
~DCE();

/**
* @brief Opens network in AT command mode
Expand Down Expand Up @@ -236,6 +243,15 @@ class DCE : public ::esp_modem::GenericModule {
int sock {-1};
int listen_sock {-1};
int data_ready_fd {-1};
static std::vector<DCE*> dce_list;
static bool network_init;
static void read_callback(uint8_t *data, size_t len)
{
for (auto dce : dce_list) {
dce->perform_at(data, len);
}
}

};
std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"

#pragma once

namespace sock_dce {

class Module: public esp_modem::GenericModule {
using esp_modem::GenericModule::GenericModule;
public:

esp_modem::command_result sync() override;
esp_modem::command_result set_echo(bool on) override;
esp_modem::command_result set_pdp_context(esp_modem::PdpContext &pdp) override;

};

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,28 @@ namespace sock_dce {

constexpr auto const *TAG = "sock_dce";

// Definition of the static member variables
std::vector<DCE*> DCE::dce_list{};
bool DCE::network_init = false;
int Responder::s_link_id = 0;
SemaphoreHandle_t Responder::s_dte_mutex{};

// Constructor - add this DCE instance to the static list
DCE::DCE(std::shared_ptr<esp_modem::DTE> dte_arg, const esp_modem_dce_config *config)
: Module(std::move(dte_arg), config)
{
dce_list.push_back(this);
}

// Destructor - remove this DCE instance from the static list
DCE::~DCE()
{
auto it = std::find(dce_list.begin(), dce_list.end(), this);
if (it != dce_list.end()) {
dce_list.erase(it);
}
}


bool DCE::perform_sock()
{
Expand Down Expand Up @@ -61,13 +83,22 @@ bool DCE::perform_sock()

void DCE::perform_at(uint8_t *data, size_t len)
{
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_VERBOSE);
std::string_view resp_sv((char *)data, len);
at.check_urc(state, resp_sv);
if (state == status::IDLE) {
return;
}
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_INFO);
switch (at.process_data(state, data, len)) {
case Responder::ret::OK:
ESP_LOGW(TAG, "GIVE data %d", at.link_id);
xSemaphoreGive(at.s_dte_mutex);
state = status::IDLE;
signal.set(IDLE);
return;
case Responder::ret::FAIL:
ESP_LOGW(TAG, "GIVE data %d", at.link_id);
xSemaphoreGive(at.s_dte_mutex);
state = status::FAILED;
signal.set(IDLE);
return;
Expand All @@ -82,10 +113,14 @@ void DCE::perform_at(uint8_t *data, size_t len)
std::string_view response((char *)data, len);
switch (at.check_async_replies(state, response)) {
case Responder::ret::OK:
ESP_LOGW(TAG, "GIVE command %d", at.link_id);
xSemaphoreGive(at.s_dte_mutex);
state = status::IDLE;
signal.set(IDLE);
return;
case Responder::ret::FAIL:
ESP_LOGW(TAG, "GIVE command %d", at.link_id);
xSemaphoreGive(at.s_dte_mutex);
state = status::FAILED;
signal.set(IDLE);
return;
Expand Down Expand Up @@ -131,6 +166,9 @@ bool DCE::at_to_sock()
close_sock();
return false;
}
ESP_LOGI(TAG, "TAKE RECV %d", at.link_id);
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
ESP_LOGE(TAG, "TAKE RECV %d", at.link_id);
state = status::RECEIVING;
at.start_receiving(at.get_buf_len());
return true;
Expand All @@ -139,8 +177,8 @@ bool DCE::at_to_sock()
bool DCE::sock_to_at()
{
ESP_LOGD(TAG, "socket read: data available");
if (!signal.wait(IDLE, 1000)) {
ESP_LOGE(TAG, "Failed to get idle");
if (!signal.wait(IDLE, 5000)) {
ESP_LOGE(TAG, "Failed to get idle 2");
close_sock();
return false;
}
Expand All @@ -149,6 +187,9 @@ bool DCE::sock_to_at()
close_sock();
return false;
}
ESP_LOGI(TAG, "TAKE SEND %d", at.link_id);
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
ESP_LOGE(TAG, "TAKE SEND %d", at.link_id);
state = status::SENDING;
int len = ::recv(sock, at.get_buf(), at.get_buf_len(), 0);
if (len < 0) {
Expand Down Expand Up @@ -224,12 +265,17 @@ void DCE::start_listening(int port)

bool DCE::connect(std::string host, int port)
{
dte->on_read(nullptr);
tcp_close();
dte->on_read([this](uint8_t *data, size_t len) {
this->perform_at(data, len);
return esp_modem::command_result::TIMEOUT;
});
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
assert(data_ready_fd > 0);
// dte->on_read(nullptr);
// tcp_close();
// dte->on_read([](uint8_t *data, size_t len) {
// read_callback(data, len);
// return esp_modem::command_result::TIMEOUT;
// });
ESP_LOGI(TAG, "TAKE CONNECT %d", at.link_id);
xSemaphoreTake(at.s_dte_mutex, portMAX_DELAY);
ESP_LOGE(TAG, "TAKE CONNECT %d", at.link_id);
if (!at.start_connecting(host, port)) {
ESP_LOGE(TAG, "Unable to start connecting");
dte->on_read(nullptr);
Expand All @@ -241,12 +287,15 @@ bool DCE::connect(std::string host, int port)

bool DCE::init()
{
if (network_init) {
return true;
}
network_init = true;
Responder::s_dte_mutex = xSemaphoreCreateBinary();
xSemaphoreGive(at.s_dte_mutex);
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
esp_vfs_eventfd_register(&config);

data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
assert(data_ready_fd > 0);

dte->on_read(nullptr);
const int retries = 5;
int i = 0;
Expand Down Expand Up @@ -287,6 +336,10 @@ bool DCE::init()
esp_modem::Task::Delay(5000);
}
ESP_LOGI(TAG, "Got IP %s", ip_addr.c_str());
dte->on_read([](uint8_t *data, size_t len) {
read_callback(data, len);
return esp_modem::command_result::TIMEOUT;
});
return true;
}

Expand Down
Loading
Loading