diff --git a/components/esp_modem/examples/modem_tcp_client/main/modem_client.cpp b/components/esp_modem/examples/modem_tcp_client/main/modem_client.cpp index bfbde426b..5d3011ecb 100644 --- a/components/esp_modem/examples/modem_tcp_client/main/modem_client.cpp +++ b/components/esp_modem/examples/modem_tcp_client/main/modem_client.cpp @@ -97,7 +97,7 @@ extern "C" void app_main(void) assert(dte); /* Configure the DCE */ - esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("lpwa.vodafone.com"); + esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_APN); /* create the DCE and initialize network manually (using AT commands) */ auto dce = sock_dce::create(&dce_config, std::move(dte)); @@ -106,10 +106,10 @@ extern "C" void app_main(void) return; } - dce->init(1883); + dce->init_sock(8883); esp_mqtt_client_config_t mqtt_config = {}; #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - mqtt_config.broker.address.uri = "mqtt://127.0.0.1"; + mqtt_config.broker.address.uri = "mqtts://127.0.0.1"; mqtt_config.session.message_retransmit_timeout = 10000; #else mqtt_config.uri = "mqtt://127.0.0.1"; @@ -118,13 +118,13 @@ extern "C" void app_main(void) esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config); esp_mqtt_client_register_event(mqtt_client, static_cast(ESP_EVENT_ANY_ID), mqtt_event_handler, NULL); esp_mqtt_client_start(mqtt_client); - if (!dce->start(BROKER_URL, 1883)) { + if (!dce->start(BROKER_URL, 8883)) { ESP_LOGE(TAG, "Failed to start DCE"); return; } while (1) { - while (dce->perform()) { - ESP_LOGD(TAG, "...performing"); + while (dce->perform_sock()) { + ESP_LOGV(TAG, "...performing"); } ESP_LOGE(TAG, "Loop exit.. retrying"); // handle disconnections errors diff --git a/components/esp_modem/examples/modem_tcp_client/main/sock_commands_bg96.cpp b/components/esp_modem/examples/modem_tcp_client/main/sock_commands_bg96.cpp index 3f8c56d18..9d79d7e38 100644 --- a/components/esp_modem/examples/modem_tcp_client/main/sock_commands_bg96.cpp +++ b/components/esp_modem/examples/modem_tcp_client/main/sock_commands_bg96.cpp @@ -28,7 +28,7 @@ command_result net_open(CommandableIf *t) if (out.find("+QISTATE: 0") != std::string::npos) { ESP_LOGV(TAG, "%s", out.data() ); ESP_LOGD(TAG, "Already there"); - return command_result::OK; + return command_result::FAIL; } else if (out.empty()) { return dce_commands::generic_command(t, "AT+QIACT=1\r", "OK", "ERROR", 150000); } @@ -38,6 +38,8 @@ command_result net_open(CommandableIf *t) command_result net_close(CommandableIf *t) { ESP_LOGV(TAG, "%s", __func__ ); + dce_commands::generic_command(t, "AT+QICLOSE=0\r", "OK", "ERROR", 10000); + esp_modem::Task::Delay(1000); return dce_commands::generic_command(t, "AT+QIDEACT=1\r", "OK", "ERROR", 40000); } @@ -104,103 +106,131 @@ command_result get_ip(CommandableIf *t, std::string &ip) namespace sock_dce { -void Listener::start_sending(size_t len) +void Responder::start_sending(size_t len) { data_to_send = len; send_stat = 0; send_cmd("AT+QISEND=0," + std::to_string(len) + "\r"); } -void Listener::start_receiving(size_t len) +void Responder::start_receiving(size_t len) { - send_cmd("AT+QIRD=0," + std::to_string(size) + "\r"); + send_cmd("AT+QIRD=0," + std::to_string(len) + "\r"); } -bool Listener::start_connecting(std::string host, int port) +bool Responder::start_connecting(std::string host, int port) { send_cmd(R"(AT+QIOPEN=1,0,"TCP",")" + host + "\"," + std::to_string(port) + "\r"); return true; } -Listener::state Listener::recv(uint8_t *data, size_t len) +Responder::ret Responder::recv(uint8_t *data, size_t len) { - const size_t MIN_MESSAGE = 6; - const std::string_view head = "+QIRD: "; - auto head_pos = (char *)std::search(data, data + len, head.begin(), head.end()); - if (head_pos == nullptr) { - return state::FAIL; - } + const int MIN_MESSAGE = 6; + size_t actual_len = 0; + auto *recv_data = (char *)data; + if (data_to_recv == 0) { + const std::string_view head = "+QIRD: "; + auto head_pos = std::search(recv_data, recv_data + len, head.begin(), head.end()); + if (head_pos == nullptr) { + return ret::FAIL; + } - auto next_nl = (char *)memchr(head_pos + head.size(), '\n', MIN_MESSAGE); - if (next_nl == nullptr) { - return state::FAIL; - } + auto next_nl = (char *)memchr(head_pos + head.size(), '\n', MIN_MESSAGE); + if (next_nl == nullptr) { + return ret::FAIL; + } - size_t actual_len; - if (std::from_chars(head_pos + head.size(), next_nl, actual_len).ec == std::errc::invalid_argument) { - ESP_LOGE(TAG, "cannot convert"); - return state::FAIL; - } + if (std::from_chars(head_pos + head.size(), next_nl, actual_len).ec == std::errc::invalid_argument) { + ESP_LOGE(TAG, "cannot convert"); + return ret::FAIL; + } - ESP_LOGD(TAG, "Received: actual len=%d", actual_len); - if (actual_len == 0) { - ESP_LOGD(TAG, "no data received"); - return state::FAIL; - } + ESP_LOGD(TAG, "Received: actual len=%d", actual_len); + if (actual_len == 0) { + ESP_LOGD(TAG, "no data received"); + return ret::FAIL; + } - // TODO improve : compare *actual_len* & data size (to be sure that received data is equal to *actual_len*) - if (actual_len > size) { - ESP_LOGE(TAG, "TOO BIG"); - return state::FAIL; + if (actual_len > buffer_size) { + ESP_LOGE(TAG, "TOO BIG"); + return ret::FAIL; + } + + recv_data = next_nl + 1; + auto first_data_len = len - (recv_data - (char *)data) /* minus size of the command marker */; + if (actual_len > first_data_len) { + ::send(sock, recv_data, first_data_len, 0); + data_to_recv = actual_len - first_data_len; + return ret::NEED_MORE_DATA; + } + ::send(sock, recv_data, actual_len, 0); + } else if (data_to_recv > len) { // continue sending + ::send(sock, recv_data, len, 0); + data_to_recv -= len; + return ret::NEED_MORE_DATA; + } else if (data_to_recv <= len) { // last read -> looking for "OK" marker + ::send(sock, recv_data, data_to_recv, 0); + actual_len = data_to_recv; } - ::send(sock, next_nl + 1, actual_len, 0); // "OK" after the data - auto last_pos = (char *)memchr(next_nl + 1 + actual_len, 'O', MIN_MESSAGE); - if (last_pos == nullptr || last_pos[1] != 'K') { - return state::FAIL; + char *last_pos = nullptr; + if (actual_len + 1 + 2 /* OK */ > len) { + last_pos = (char *)memchr(recv_data + 1 + actual_len, 'O', MIN_MESSAGE); + if (last_pos == nullptr || last_pos[1] != 'K') { + data_to_recv = 0; + return ret::FAIL; + } } - if ((char *)data + len - last_pos > MIN_MESSAGE) { + if (last_pos != nullptr && (char *)data + len - last_pos - 2 > MIN_MESSAGE) { // check for async replies after the Recv header std::string_view response((char *)last_pos + 2 /* OK */, (char *)data + len - last_pos); - check_async_replies(response); + check_async_replies(status::RECEIVING, response); } - return state::OK; + // check if some other data? + start_receiving(0); + data_to_recv = 0; + return ret::OK; } -Listener::state Listener::send(uint8_t *data, size_t len) +Responder::ret Responder::send(uint8_t *data, size_t len) { - if (send_stat == 0) { + if (send_stat < 3) { if (memchr(data, '>', len) == NULL) { + if (send_stat++ < 2) { + return Responder::ret::NEED_MORE_DATA; + } ESP_LOGE(TAG, "Missed >"); - return state::FAIL; + return ret::FAIL; } auto written = dte->write(&buffer[0], data_to_send); if (written != data_to_send) { ESP_LOGE(TAG, "written %d (%d)...", written, len); - return state::FAIL; + return ret::FAIL; } data_to_send = 0; - send_stat++; + send_stat = 3; } - return Listener::state::IN_PROGRESS; + return Responder::ret::IN_PROGRESS; } -Listener::state Listener::send(std::string_view response) +Responder::ret Responder::send(std::string_view response) { - if (send_stat == 1) { + if (send_stat == 3) { if (response.find("SEND OK") != std::string::npos) { send_cmd("AT+QISEND=0,0\r"); send_stat++; + return ret::IN_PROGRESS; } else if (response.find("SEND FAIL") != std::string::npos) { ESP_LOGE(TAG, "Sending buffer full"); - return state::FAIL; + return ret::FAIL; } else if (response.find("ERROR") != std::string::npos) { ESP_LOGE(TAG, "Failed to sent"); - return state::FAIL; + return ret::FAIL; } - } else if (send_stat == 2) { + } else if (send_stat == 4) { constexpr std::string_view head = "+QISEND: "; if (response.find(head) != std::string::npos) { // Parsing +QISEND: ,, @@ -215,7 +245,7 @@ Listener::state Listener::send(std::string_view response) size_t value; if (std::from_chars(response.data(), next_comma, value).ec == std::errc::invalid_argument) { ESP_LOGE(TAG, "cannot convert"); - return state::FAIL; + return ret::FAIL; } switch (property++) { @@ -224,49 +254,94 @@ Listener::state Listener::send(std::string_view response) case 1: ack = value; break; default: - return state::FAIL; + return ret::FAIL; } response = response.substr(pos + 1); } if (std::from_chars(response.data(), response.data() + pos, unack).ec == std::errc::invalid_argument) { - return state::FAIL; + return ret::FAIL; } - // TODO improve : need check *total* & *ack* values, or loop (every 5 sec) with 90s or 120s timeout if (ack < total) { - ESP_LOGE(TAG, "all sending data are not ack (missing %d bytes acked)", (total - ack)); + ESP_LOGD(TAG, "all sending data are not ack (missing %d bytes acked)", (total - ack)); + if (total - ack > 64) { + ESP_LOGW(TAG, "Need a pause: missing %d bytes acked", (total - ack)); + return ret::NEED_MORE_TIME; + } } - return state::OK; + send_stat = 0; + return ret::OK; } else if (response.find("ERROR") != std::string::npos) { ESP_LOGE(TAG, "Failed to check sending"); - return state::FAIL; + return ret::FAIL; } } - return Listener::state::IN_PROGRESS; + return Responder::ret::IN_PROGRESS; } -Listener::state Listener::connect(std::string_view response) +Responder::ret Responder::connect(std::string_view response) { if (response.find("+QIOPEN: 0,0") != std::string::npos) { ESP_LOGI(TAG, "Connected!"); - return state::OK; + return ret::OK; } if (response.find("ERROR") != std::string::npos) { ESP_LOGE(TAG, "Failed to open"); - return state::FAIL; + return ret::FAIL; } - return Listener::state::IN_PROGRESS; + return Responder::ret::IN_PROGRESS; } -void Listener::check_async_replies(std::string_view &response) const +Responder::ret Responder::check_async_replies(status state, std::string_view &response) { ESP_LOGD(TAG, "response %.*s", static_cast(response.size()), response.data()); if (response.find("+QIURC: \"recv\",0") != std::string::npos) { uint64_t data_ready = 1; write(data_ready_fd, &data_ready, sizeof(data_ready)); ESP_LOGD(TAG, "Got data on modem!"); + } else if (response.find("+QIRD: ") != std::string::npos) { + static constexpr std::string_view head = "+QIRD: "; + size_t head_pos = response.find(head); + // Parsing +QIURC: ,, + response = response.substr(head_pos + head.size()); + int next_cr = response.find('\r'); + if (next_cr != std::string::npos) { + response = response.substr(next_cr - 2, next_cr); + if (response.find(",0") != std::string::npos) { + ESP_LOGV(TAG, "Receiving done"); + } else { + uint64_t data_ready = 1; + write(data_ready_fd, &data_ready, sizeof(data_ready)); + ESP_LOGD(TAG, "Got data on modem!"); + } + } + } else if (response.find("+QIURC: \"closed\",0") != std::string::npos) { + return ret::FAIL; } + if (state == status::SENDING) { + return send(response); + } else if (state == status::CONNECTING) { + return connect(response); + } + return ret::IN_PROGRESS; +} + +Responder::ret Responder::process_data(status state, uint8_t *data, size_t len) +{ + if (state == status::SENDING) { + return send(data, len); + } + if (state == status::RECEIVING) { + return recv(data, len); + } + return Responder::ret::IN_PROGRESS; +} + +status Responder::pending() +{ + send_cmd("AT+QISEND=0,0\r"); + return status::SENDING; } diff --git a/components/esp_modem/examples/modem_tcp_client/main/sock_commands_sim7600.cpp b/components/esp_modem/examples/modem_tcp_client/main/sock_commands_sim7600.cpp index fa146226f..e94f2ac95 100644 --- a/components/esp_modem/examples/modem_tcp_client/main/sock_commands_sim7600.cpp +++ b/components/esp_modem/examples/modem_tcp_client/main/sock_commands_sim7600.cpp @@ -6,14 +6,15 @@ #include #include +#include #include "sock_commands.hpp" #include "cxx_include/esp_modem_command_library_utils.hpp" #include "sock_dce.hpp" -namespace sock_commands { - static const char *TAG = "sock_commands"; +namespace sock_commands { + using namespace esp_modem; command_result net_open(CommandableIf *term) @@ -27,12 +28,17 @@ command_result net_open(CommandableIf *term) ESP_LOGV(TAG, "%s", response.data() ); if (response.find("+NETOPEN: 1") != std::string::npos) { ESP_LOGD(TAG, "Already there"); - return command_result::OK; + ret = command_result::OK; } else if (response.find("+NETOPEN: 0") != std::string::npos) { ESP_LOGD(TAG, "Need to setup"); - return dce_commands::generic_command(term, "AT+NETOPEN\r", "+NETOPEN: 1", "+NETOPEN: 0", 10000); + ret = dce_commands::generic_command(term, "AT+NETOPEN\r", "+NETOPEN: 1", "+NETOPEN: 0", 10000); + } else { + return command_result::FAIL; } - return command_result::FAIL; + if (ret != command_result::OK) { + return ret; + } + return dce_commands::generic_command(term, "AT+CIPRXGET=1\r", "OK", "ERROR", 5000); } command_result net_close(CommandableIf *term) @@ -186,28 +192,25 @@ command_result set_rx_mode(CommandableIf *term, int mode) namespace sock_dce { -void Listener::start_sending(size_t len) +void Responder::start_sending(size_t len) { data_to_send = len; send_stat = 0; send_cmd("AT+CIPSEND=0," + std::to_string(len) + "\r"); } -void Listener::start_receiving(size_t len) +void Responder::start_receiving(size_t len) { - send_cmd("AT+CIPRXGET=2,0," + std::to_string(size) + "\r"); + send_cmd("AT+CIPRXGET=2,0," + std::to_string(len) + "\r"); } -bool Listener::start_connecting(std::string host, int port) +bool Responder::start_connecting(std::string host, int port) { - if (esp_modem::dce_commands::generic_command(dte.get(), "AT+CIPRXGET=1\r", "OK", "ERROR", 5000) != esp_modem::command_result::OK) { - return false; - } send_cmd(R"(AT+CIPOPEN=0,"TCP",")" + host + "\"," + std::to_string(port) + "\r"); return true; } -Listener::state Listener::recv(uint8_t *data, size_t len) +Responder::ret Responder::recv(uint8_t *data, size_t len) { const int MIN_MESSAGE = 6; size_t actual_len = 0; @@ -216,40 +219,37 @@ Listener::state Listener::recv(uint8_t *data, size_t len) static constexpr std::string_view head = "+CIPRXGET: 2,0,"; auto head_pos = std::search(recv_data, recv_data + len, head.begin(), head.end()); if (head_pos == nullptr) { - return state::FAIL; + return ret::FAIL; } -// state = status::RECEIVING_FAILED; -// signal.set(IDLE); -// return; -// } + if (head_pos - (char *)data > MIN_MESSAGE) { // check for async replies before the Recv header std::string_view response((char *)data, head_pos - (char *)data); - check_async_replies(response); + check_async_replies(status::RECEIVING, response); } auto next_comma = (char *)memchr(head_pos + head.size(), ',', MIN_MESSAGE); if (next_comma == nullptr) { - return state::FAIL; + return ret::FAIL; } if (std::from_chars(head_pos + head.size(), next_comma, actual_len).ec == std::errc::invalid_argument) { ESP_LOGE(TAG, "cannot convert"); - return state::FAIL; + return ret::FAIL; } auto next_nl = (char *)memchr(next_comma, '\n', 8 /* total_len size (~4) + markers */); if (next_nl == nullptr) { ESP_LOGE(TAG, "not found"); - return state::FAIL; + return ret::FAIL; } - if (actual_len > size) { + if (actual_len > buffer_size) { ESP_LOGE(TAG, "TOO BIG"); - return state::FAIL; + return ret::FAIL; } size_t total_len = 0; if (std::from_chars(next_comma + 1, next_nl - 1, total_len).ec == std::errc::invalid_argument) { ESP_LOGE(TAG, "cannot convert"); - return state::FAIL; + return ret::FAIL; } read_again = (total_len > 0); recv_data = next_nl + 1; @@ -257,13 +257,13 @@ Listener::state Listener::recv(uint8_t *data, size_t len) if (actual_len > first_data_len) { ::send(sock, recv_data, first_data_len, 0); data_to_recv = actual_len - first_data_len; - return state::IN_PROGRESS; + return ret::NEED_MORE_DATA; } ::send(sock, recv_data, actual_len, 0); } else if (data_to_recv > len) { // continue sending ::send(sock, recv_data, len, 0); data_to_recv -= len; - return state::IN_PROGRESS; + return ret::NEED_MORE_DATA; } else if (data_to_recv <= len) { // last read -> looking for "OK" marker ::send(sock, recv_data, data_to_recv, 0); actual_len = data_to_recv; @@ -275,73 +275,73 @@ Listener::state Listener::recv(uint8_t *data, size_t len) last_pos = (char *)memchr(recv_data + 1 + actual_len, 'O', MIN_MESSAGE); if (last_pos == nullptr || last_pos[1] != 'K') { data_to_recv = 0; - return state::FAIL; + return ret::FAIL; } } - if (last_pos != nullptr && (char *)data + len - last_pos > MIN_MESSAGE) { + if (last_pos != nullptr && (char *)data + len - last_pos - 2 > MIN_MESSAGE) { // check for async replies after the Recv header std::string_view response((char *)last_pos + 2 /* OK */, (char *)data + len - last_pos - 2); - check_async_replies(response); + check_async_replies(status::RECEIVING, response); } data_to_recv = 0; if (read_again) { uint64_t data_ready = 1; write(data_ready_fd, &data_ready, sizeof(data_ready)); } - return state::OK; + return ret::OK; } -Listener::state Listener::send(uint8_t *data, size_t len) +Responder::ret Responder::send(uint8_t *data, size_t len) { if (send_stat == 0) { if (memchr(data, '>', len) == NULL) { ESP_LOGE(TAG, "Missed >"); - return state::FAIL; + return ret::FAIL; } auto written = dte->write(&buffer[0], data_to_send); if (written != data_to_send) { ESP_LOGE(TAG, "written %d (%d)...", written, len); - return state::FAIL; + return ret::FAIL; } data_to_send = 0; uint8_t ctrl_z = '\x1A'; dte->write(&ctrl_z, 1); send_stat++; - return state::IN_PROGRESS; + return ret::IN_PROGRESS; } - return Listener::state::IN_PROGRESS; + return Responder::ret::IN_PROGRESS; } -Listener::state Listener::send(std::string_view response) +Responder::ret Responder::send(std::string_view response) { if (send_stat == 1) { if (response.find("+CIPSEND:") != std::string::npos) { send_stat = 0; - return state::OK; + return ret::OK; } if (response.find("ERROR") != std::string::npos) { ESP_LOGE(TAG, "Failed to sent"); send_stat = 0; - return state::FAIL; + return ret::FAIL; } } - return Listener::state::IN_PROGRESS; + return Responder::ret::IN_PROGRESS; } -Listener::state Listener::connect(std::string_view response) +Responder::ret Responder::connect(std::string_view response) { if (response.find("+CIPOPEN: 0,0") != std::string::npos) { ESP_LOGI(TAG, "Connected!"); - return state::OK; + return ret::OK; } if (response.find("ERROR") != std::string::npos) { ESP_LOGE(TAG, "Failed to open"); - return state::FAIL; + return ret::FAIL; } - return Listener::state::IN_PROGRESS; + return Responder::ret::IN_PROGRESS; } -void Listener::check_async_replies(std::string_view &response) const +Responder::ret Responder::check_async_replies(status state, std::string_view &response) { ESP_LOGD(TAG, "response %.*s", static_cast(response.size()), response.data()); if (response.find("+CIPRXGET: 1") != std::string::npos) { @@ -349,8 +349,30 @@ void Listener::check_async_replies(std::string_view &response) const write(data_ready_fd, &data_ready, sizeof(data_ready)); ESP_LOGD(TAG, "Got data on modem!"); } + if (state == status::SENDING) { + return send(response); + } else if (state == status::CONNECTING) { + return connect(response); + } + return ret::IN_PROGRESS; } +Responder::ret Responder::process_data(status state, uint8_t *data, size_t len) +{ + if (state == status::SENDING) { + return send(data, len); + } + if (state == status::RECEIVING) { + return recv(data, len); + } + return Responder::ret::IN_PROGRESS; +} + +status Responder::pending() +{ + return status::PENDING; +} + } // sock_dce diff --git a/components/esp_modem/examples/modem_tcp_client/main/sock_dce.cpp b/components/esp_modem/examples/modem_tcp_client/main/sock_dce.cpp index ec189f206..17fba4125 100644 --- a/components/esp_modem/examples/modem_tcp_client/main/sock_dce.cpp +++ b/components/esp_modem/examples/modem_tcp_client/main/sock_dce.cpp @@ -16,7 +16,7 @@ namespace sock_dce { constexpr auto const *TAG = "sock_dce"; -bool DCE::perform() +bool DCE::perform_sock() { if (listen_sock == -1) { ESP_LOGE(TAG, "Listening socket not ready"); @@ -32,13 +32,18 @@ bool DCE::perform() .tv_sec = 0, .tv_usec = 500000, }; + if (state == status::PENDING) { + vTaskDelay(pdMS_TO_TICKS(500)); + state = at.pending(); + return true; + } fd_set fdset; FD_ZERO(&fdset); FD_SET(sock, &fdset); FD_SET(data_ready_fd, &fdset); int s = select(std::max(sock, data_ready_fd) + 1, &fdset, nullptr, nullptr, &tv); if (s == 0) { - ESP_LOGD(TAG, "perform select timeout..."); + ESP_LOGV(TAG, "perform select timeout..."); return true; } else if (s < 0) { ESP_LOGE(TAG, "select error %d", errno); @@ -54,68 +59,42 @@ bool DCE::perform() return true; } -void DCE::forwarding(uint8_t *data, size_t len) +void DCE::perform_at(uint8_t *data, size_t len) { - ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_DEBUG); - if (state == status::SENDING) { - switch (at.send(data, len)) { - case Listener::state::OK: - state = status::IDLE; - signal.set(IDLE); - return; - case Listener::state::FAIL: - state = status::SENDING_FAILED; - signal.set(IDLE); - return; - case Listener::state::IN_PROGRESS: - break; -// return; - } - } else if (state == status::RECEIVING) { - switch (at.recv(data, len)) { - case Listener::state::OK: - state = status::IDLE; - signal.set(IDLE); - return; - case Listener::state::FAIL: - state = status::RECEIVING_FAILED; - signal.set(IDLE); - return; - case Listener::state::IN_PROGRESS: -// break; - return; - } + ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_VERBOSE); + switch (at.process_data(state, data, len)) { + case Responder::ret::OK: + state = status::IDLE; + signal.set(IDLE); + return; + case Responder::ret::FAIL: + state = status::FAILED; + signal.set(IDLE); + return; + case Responder::ret::NEED_MORE_DATA: + return; + case Responder::ret::IN_PROGRESS: + break; + case Responder::ret::NEED_MORE_TIME: + state = status::PENDING; + return; } std::string_view response((char *)data, len); - at.check_async_replies(response); - // Notification about Data Ready could come any time - if (state == status::SENDING) { - switch (at.send(response)) { - case Listener::state::OK: - state = status::IDLE; - signal.set(IDLE); - return; - case Listener::state::FAIL: - state = status::SENDING_FAILED; - signal.set(IDLE); - return; - case Listener::state::IN_PROGRESS: - break; - } - } - if (state == status::CONNECTING) { - switch (at.connect(response)) { - case Listener::state::OK: - state = status::IDLE; - signal.set(IDLE); - return; - case Listener::state::FAIL: - state = status::CONNECTION_FAILED; - signal.set(IDLE); - return; - case Listener::state::IN_PROGRESS: - break; - } + switch (at.check_async_replies(state, response)) { + case Responder::ret::OK: + state = status::IDLE; + signal.set(IDLE); + return; + case Responder::ret::FAIL: + state = status::FAILED; + signal.set(IDLE); + return; + case Responder::ret::NEED_MORE_TIME: + state = status::PENDING; + return; + case Responder::ret::NEED_MORE_DATA: + case Responder::ret::IN_PROGRESS: + break; } } @@ -125,6 +104,7 @@ void DCE::close_sock() close(sock); sock = -1; } + dte->on_read(nullptr); const int retries = 5; int i = 0; while (net_close() != esp_modem::command_result::OK) { @@ -152,7 +132,7 @@ bool DCE::at_to_sock() return false; } state = status::RECEIVING; - at.start_receiving(size); + at.start_receiving(at.get_buf_len()); return true; } @@ -170,7 +150,7 @@ bool DCE::sock_to_at() return false; } state = status::SENDING; - int len = ::recv(sock, &buffer[0], size, 0); + int len = ::recv(sock, at.get_buf(), at.get_buf_len(), 0); if (len < 0) { ESP_LOGE(TAG, "read error %d", errno); close_sock(); @@ -180,7 +160,7 @@ bool DCE::sock_to_at() close_sock(); return false; } - ESP_LOG_BUFFER_HEXDUMP(TAG, &buffer[0], len, ESP_LOG_VERBOSE); + ESP_LOG_BUFFER_HEXDUMP(TAG, at.get_buf(), len, ESP_LOG_VERBOSE); at.start_sending(len); return true; } @@ -212,7 +192,7 @@ bool DCE::accept_sock() return false; } -void DCE::init(int port) +void DCE::init_sock(int port) { esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT(); esp_vfs_eventfd_register(&config); @@ -228,7 +208,7 @@ void DCE::init(int port) int opt = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); ESP_LOGI(TAG, "Socket created"); - struct sockaddr_in addr = { }; + struct sockaddr_in addr = { }; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -253,7 +233,7 @@ bool DCE::start(std::string host, int port) dte->on_read(nullptr); tcp_close(); dte->on_read([this](uint8_t *data, size_t len) { - this->forwarding(data, len); + this->perform_at(data, len); return esp_modem::command_result::TIMEOUT; }); if (!at.start_connecting(host, port)) { @@ -267,6 +247,7 @@ bool DCE::start(std::string host, int port) bool DCE::init_network() { + dte->on_read(nullptr); const int retries = 5; int i = 0; while (sync() != esp_modem::command_result::OK) { @@ -292,6 +273,7 @@ bool DCE::init_network() ESP_LOGE(TAG, "Failed to open network"); return false; } + net_close(); esp_modem::Task::Delay(1000); } ESP_LOGD(TAG, "Network opened"); @@ -341,9 +323,4 @@ DECLARE_SOCK_COMMANDS(return_type name(...) ) #undef ESP_MODEM_DECLARE_DCE_COMMAND - - - - - } // namespace sock_dce diff --git a/components/esp_modem/examples/modem_tcp_client/main/sock_dce.hpp b/components/esp_modem/examples/modem_tcp_client/main/sock_dce.hpp index 9587aa855..37dd19223 100644 --- a/components/esp_modem/examples/modem_tcp_client/main/sock_dce.hpp +++ b/components/esp_modem/examples/modem_tcp_client/main/sock_dce.hpp @@ -14,30 +14,50 @@ namespace sock_dce { -static constexpr size_t size = 512; -class Listener { +enum class status { + IDLE, + CONNECTING, + SENDING, + RECEIVING, + FAILED, + PENDING +}; + +class Responder { public: - enum class state { - OK, FAIL, IN_PROGRESS + enum class ret { + OK, FAIL, IN_PROGRESS, NEED_MORE_DATA, NEED_MORE_TIME }; - Listener(std::array &b, int &s, int &ready_fd, std::shared_ptr &dte_arg): - buffer(b), sock(s), data_ready_fd(ready_fd), dte(dte_arg) {} - state recv(uint8_t *data, size_t len); - state send(uint8_t *data, size_t len); - state send(std::string_view response); - state connect(std::string_view response); - void check_async_replies(std::string_view &response) const; + Responder(int &s, int &ready_fd, std::shared_ptr &dte_arg): + sock(s), data_ready_fd(ready_fd), dte(dte_arg) {} + ret process_data(status state, uint8_t *data, size_t len); + ret check_async_replies(status state, std::string_view &response); void start_sending(size_t len); void start_receiving(size_t len); bool start_connecting(std::string host, int port); + status pending(); + uint8_t *get_buf() + { + return &buffer[0]; + } + size_t get_buf_len() + { + return buffer_size; + } private: + static constexpr size_t buffer_size = 512; + + ret recv(uint8_t *data, size_t len); + ret send(uint8_t *data, size_t len); + ret send(std::string_view response); + ret connect(std::string_view response); void send_cmd(std::string_view command) { dte->write((uint8_t *) command.begin(), command.size()); } - std::array &buffer; + std::array buffer; size_t data_to_recv = 0; bool read_again = false; int &sock; @@ -61,9 +81,9 @@ esp_modem::return_type name(__VA_ARGS__); bool init_network(); bool start(std::string host, int port); - void init(int port); + void init_sock(int port); - bool perform(); + bool perform_sock(); private: esp_modem::SignalGroup signal; @@ -73,21 +93,11 @@ private: bool sock_to_at(); bool at_to_sock(); - void forwarding(uint8_t *data, size_t len); + void perform_at(uint8_t *data, size_t len); - enum class status { - IDLE, - CONNECTING, - CONNECTION_FAILED, - SENDING, - SENDING_FAILED, - RECEIVING, - RECEIVING_FAILED - }; status state{status::IDLE}; static constexpr uint8_t IDLE = 1; - std::array buffer; - Listener at{buffer, sock, data_ready_fd, dte}; + Responder at{sock, data_ready_fd, dte}; int sock {-1}; int listen_sock {-1}; int data_ready_fd {-1};