fix(modem): AT-only example: initial adaptation to BG96

Plus rework a little to support implementation of multiple devices
This commit is contained in:
Jonathan Dreyer
2023-01-22 19:03:07 +01:00
committed by David Cermak
parent 7547267336
commit ceedcfca23
7 changed files with 482 additions and 223 deletions

View File

@ -1,5 +1,11 @@
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)
endif()
idf_component_register(SRCS "modem_client.cpp"
"sock_dce.cpp"
"sock_commands.cpp"
"${device_srcs}"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -5,11 +5,6 @@ menu "Example Configuration"
default EXAMPLE_MODEM_DEVICE_BG96
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SIM800
bool "SIM800"
help
SIMCom SIM800L is a GSM/GPRS module.
It supports Quad-band 850/900/1800/1900MHz.
config EXAMPLE_MODEM_DEVICE_BG96
bool "BG96"
help
@ -26,53 +21,6 @@ menu "Example Configuration"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_MODEM_PPP_AUTH_USERNAME
string "Set username for authentication"
default "espressif"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set username for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
string "Set password for authentication"
default "esp32"
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
help
Set password for PPP Authentication.
config EXAMPLE_MODEM_PPP_AUTH_NONE
bool "Skip PPP authentication"
default n
help
Set to true for the PPP client to skip authentication
config EXAMPLE_SEND_MSG
bool "Short message (SMS)"
default n
help
Select this, the modem will send a short message before power off.
if EXAMPLE_SEND_MSG
config EXAMPLE_SEND_MSG_PEER_PHONE_NUMBER
string "Peer Phone Number (with area code)"
default "+8610086"
help
Enter the peer phone number that you want to send message to.
endif
config EXAMPLE_NEED_SIM_PIN
bool "SIM PIN needed"
default n
help
Enable to set SIM PIN before starting the example
config EXAMPLE_SIM_PIN
string "Set SIM PIN"
default "1234"
depends on EXAMPLE_NEED_SIM_PIN
help
Pin to unlock the SIM
menu "UART Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"

View File

@ -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(CONFIG_EXAMPLE_MODEM_APN);
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("lpwa.vodafone.com");
/* 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(8883);
dce->init(1883);
esp_mqtt_client_config_t mqtt_config = {};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
mqtt_config.broker.address.uri = "mqtts://127.0.0.1";
mqtt_config.broker.address.uri = "mqtt://127.0.0.1";
mqtt_config.session.message_retransmit_timeout = 10000;
#else
mqtt_config.uri = "mqtt://127.0.0.1";
@ -118,7 +118,7 @@ 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_mqtt_event_id_t>(ESP_EVENT_ANY_ID), mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
if (!dce->start(BROKER_URL, 8883)) {
if (!dce->start(BROKER_URL, 1883)) {
ESP_LOGE(TAG, "Failed to start DCE");
return;
}

View File

@ -0,0 +1,273 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <charconv>
#include <cstring>
#include <sys/socket.h>
#include "sock_commands.hpp"
#include "cxx_include/esp_modem_command_library_utils.hpp"
#include "sock_dce.hpp"
static const char *TAG = "sock_commands";
namespace sock_commands {
using namespace esp_modem;
command_result net_open(CommandableIf *t)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string out;
auto ret = dce_commands::generic_get_string(t, "AT+QISTATE?\r", out, 1000);
if (ret != command_result::OK) {
return ret;
}
if (out.find("+QISTATE: 0") != std::string::npos) {
ESP_LOGV(TAG, "%s", out.data() );
ESP_LOGD(TAG, "Already there");
return command_result::OK;
} else if (out.empty()) {
return dce_commands::generic_command(t, "AT+QIACT=1\r", "OK", "ERROR", 150000);
}
return command_result::FAIL;
}
command_result net_close(CommandableIf *t)
{
ESP_LOGV(TAG, "%s", __func__ );
return dce_commands::generic_command(t, "AT+QIDEACT=1\r", "OK", "ERROR", 40000);
}
command_result tcp_open(CommandableIf *t, const std::string &host, int port, int timeout)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string ip_open = R"(AT+QIOPEN=1,0,"TCP",")" + host + "\"," + std::to_string(port) + "\r";
auto ret = dce_commands::generic_command(t, ip_open, "+QIOPEN: 0,0", "ERROR", timeout);
if (ret != command_result::OK) {
ESP_LOGE(TAG, "%s Failed", __func__ );
return ret;
}
return command_result::OK;
}
command_result tcp_close(CommandableIf *t)
{
ESP_LOGV(TAG, "%s", __func__ );
return dce_commands::generic_command(t, "AT+QICLOSE=0\r", "OK", "ERROR", 10000);
}
command_result tcp_send(CommandableIf *t, uint8_t *data, size_t len)
{
ESP_LOGV(TAG, "%s", __func__ );
assert(0); // Remove when fix done
return command_result::FAIL;
}
command_result tcp_recv(CommandableIf *t, uint8_t *data, size_t len, size_t &out_len)
{
ESP_LOGV(TAG, "%s", __func__ );
assert(0); // Remove when fix done
return command_result::FAIL;
}
command_result get_ip(CommandableIf *t, std::string &ip)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string out;
auto ret = dce_commands::generic_get_string(t, "AT+QIACT?\r", out, 5000);
if (ret != command_result::OK) {
return ret;
}
auto pos = out.find("+QIACT: 1");
auto property = 0;
while (pos != std::string::npos) {
// Looking for: +QIACT: <contextID>,<context_state>,<context_type>,<IP_address>
if (property++ == 3) { // ip is after 3rd comma (as a 4rd property of QIACT string)
ip = out.substr(++pos);
// strip quotes if present
auto quote1 = ip.find('"');
auto quote2 = ip.rfind('"');
if (quote1 != std::string::npos && quote2 != std::string::npos) {
ip = ip.substr(quote1 + 1, quote2 - 1);
}
return command_result::OK;
}
pos = out.find(',', ++pos);
}
return command_result::FAIL;
}
} // sock_commands
namespace sock_dce {
void Listener::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)
{
send_cmd("AT+QIRD=0," + std::to_string(size) + "\r");
}
bool Listener::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)
{
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;
}
auto next_nl = (char *)memchr(head_pos + head.size(), '\n', MIN_MESSAGE);
if (next_nl == nullptr) {
return state::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;
}
ESP_LOGD(TAG, "Received: actual len=%d", actual_len);
if (actual_len == 0) {
ESP_LOGD(TAG, "no data received");
return state::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;
}
::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;
}
if ((char *)data + len - last_pos > 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);
}
return state::OK;
}
Listener::state Listener::send(uint8_t *data, size_t len)
{
if (send_stat == 0) {
if (memchr(data, '>', len) == NULL) {
ESP_LOGE(TAG, "Missed >");
return state::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;
}
data_to_send = 0;
send_stat++;
}
return Listener::state::IN_PROGRESS;
}
Listener::state Listener::send(std::string_view response)
{
if (send_stat == 1) {
if (response.find("SEND OK") != std::string::npos) {
send_cmd("AT+QISEND=0,0\r");
send_stat++;
} else if (response.find("SEND FAIL") != std::string::npos) {
ESP_LOGE(TAG, "Sending buffer full");
return state::FAIL;
} else if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to sent");
return state::FAIL;
}
} else if (send_stat == 2) {
constexpr std::string_view head = "+QISEND: ";
if (response.find(head) != std::string::npos) {
// Parsing +QISEND: <total_send_length>,<ackedbytes>,<unackedbytes>
size_t head_pos = response.find(head);
response = response.substr(head_pos + head.size());
int pos, property = 0;
int total = 0, ack = 0, unack = 0;
while ((pos = response.find(',')) != std::string::npos) {
auto next_comma = (char *)memchr(response.data(), ',', response.size());
// extract value
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;
}
switch (property++) {
case 0: total = value;
break;
case 1: ack = value;
break;
default:
return state::FAIL;
}
response = response.substr(pos + 1);
}
if (std::from_chars(response.data(), response.data() + pos, unack).ec == std::errc::invalid_argument) {
return state::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));
}
return state::OK;
} else if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to check sending");
return state::FAIL;
}
}
return Listener::state::IN_PROGRESS;
}
Listener::state Listener::connect(std::string_view response)
{
if (response.find("+QIOPEN: 0,0") != std::string::npos) {
ESP_LOGI(TAG, "Connected!");
return state::OK;
}
if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to open");
return state::FAIL;
}
return Listener::state::IN_PROGRESS;
}
void Listener::check_async_replies(std::string_view &response) const
{
ESP_LOGD(TAG, "response %.*s", static_cast<int>(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!");
}
}
} // sock_dce

View File

@ -8,6 +8,7 @@
#include <cstring>
#include "sock_commands.hpp"
#include "cxx_include/esp_modem_command_library_utils.hpp"
#include "sock_dce.hpp"
namespace sock_commands {
@ -181,6 +182,175 @@ command_result set_rx_mode(CommandableIf *term, int mode)
return dce_commands::generic_command(term, "AT+CIPRXGET=" + std::to_string(mode) + "\r", "OK", "ERROR", 5000);
}
} // sock_commands
namespace sock_dce {
void Listener::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)
{
send_cmd("AT+CIPRXGET=2,0," + std::to_string(size) + "\r");
}
bool Listener::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)
{
const int MIN_MESSAGE = 6;
size_t actual_len = 0;
auto *recv_data = (char *)data;
if (data_to_recv == 0) {
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;
}
// 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);
}
auto next_comma = (char *)memchr(head_pos + head.size(), ',', MIN_MESSAGE);
if (next_comma == nullptr) {
return state::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;
}
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;
}
if (actual_len > size) {
ESP_LOGE(TAG, "TOO BIG");
return state::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;
}
read_again = (total_len > 0);
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 state::IN_PROGRESS;
}
::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;
} 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;
}
// "OK" after the data
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 state::FAIL;
}
}
if (last_pos != nullptr && (char *)data + len - last_pos > 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);
}
data_to_recv = 0;
if (read_again) {
uint64_t data_ready = 1;
write(data_ready_fd, &data_ready, sizeof(data_ready));
}
return state::OK;
}
Listener::state Listener::send(uint8_t *data, size_t len)
{
if (send_stat == 0) {
if (memchr(data, '>', len) == NULL) {
ESP_LOGE(TAG, "Missed >");
return state::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;
}
data_to_send = 0;
uint8_t ctrl_z = '\x1A';
dte->write(&ctrl_z, 1);
send_stat++;
return state::IN_PROGRESS;
}
return Listener::state::IN_PROGRESS;
}
Listener::state Listener::send(std::string_view response)
{
if (send_stat == 1) {
if (response.find("+CIPSEND:") != std::string::npos) {
send_stat = 0;
return state::OK;
}
if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to sent");
send_stat = 0;
return state::FAIL;
}
}
return Listener::state::IN_PROGRESS;
}
Listener::state Listener::connect(std::string_view response)
{
if (response.find("+CIPOPEN: 0,0") != std::string::npos) {
ESP_LOGI(TAG, "Connected!");
return state::OK;
}
if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to open");
return state::FAIL;
}
return Listener::state::IN_PROGRESS;
}
void Listener::check_async_replies(std::string_view &response) const
{
ESP_LOGD(TAG, "response %.*s", static_cast<int>(response.size()), response.data());
if (response.find("+CIPRXGET: 1") != std::string::npos) {
uint64_t data_ready = 1;
write(data_ready_fd, &data_ready, sizeof(data_ready));
ESP_LOGD(TAG, "Got data on modem!");
}
}
} // sock_dce

View File

@ -68,9 +68,10 @@ void DCE::forwarding(uint8_t *data, size_t len)
signal.set(IDLE);
return;
case Listener::state::IN_PROGRESS:
return;
break;
// return;
}
} else if (state == status::RECEIVING || state == status::RECEIVING_1 ) {
} else if (state == status::RECEIVING) {
switch (at.recv(data, len)) {
case Listener::state::OK:
state = status::IDLE;
@ -81,6 +82,7 @@ void DCE::forwarding(uint8_t *data, size_t len)
signal.set(IDLE);
return;
case Listener::state::IN_PROGRESS:
// break;
return;
}
}
@ -123,6 +125,15 @@ void DCE::close_sock()
close(sock);
sock = -1;
}
const int retries = 5;
int i = 0;
while (net_close() != esp_modem::command_result::OK) {
if (i++ > retries) {
ESP_LOGE(TAG, "Failed to close network");
return;
}
esp_modem::Task::Delay(1000);
}
}
bool DCE::at_to_sock()
@ -141,7 +152,7 @@ bool DCE::at_to_sock()
return false;
}
state = status::RECEIVING;
send_cmd("AT+CIPRXGET=2,0," + std::to_string(size) + "\r");
at.start_receiving(size);
return true;
}
@ -170,8 +181,7 @@ bool DCE::sock_to_at()
return false;
}
ESP_LOG_BUFFER_HEXDUMP(TAG, &buffer[0], len, ESP_LOG_VERBOSE);
data_to_send = len;
send_cmd("AT+CIPSEND=0," + std::to_string(len) + "\r");
at.start_sending(len);
return true;
}
@ -238,30 +248,19 @@ void DCE::init(int port)
}
void Listener::check_async_replies(std::string_view &response) const
{
ESP_LOGD(TAG, "response %.*s", static_cast<int>(response.size()), response.data());
if (response.find("+CIPRXGET: 1") != std::string::npos) {
uint64_t data_ready = 1;
write(data_ready_fd, &data_ready, sizeof(data_ready));
ESP_LOGD(TAG, "Got data on modem!");
}
}
bool DCE::start(std::string host, int port)
{
dte->on_read(nullptr);
tcp_close();
if (set_rx_mode(1) != esp_modem::command_result::OK) {
ESP_LOGE(TAG, "Unable to set Rx mode");
return false;
}
dte->on_read([this](uint8_t *data, size_t len) {
this->forwarding(data, len);
return esp_modem::command_result::TIMEOUT;
});
send_cmd(R"(AT+CIPOPEN=0,"TCP",")" + host + "\"," + std::to_string(port) + "\r");
if (!at.start_connecting(host, port)) {
ESP_LOGE(TAG, "Unable to start connecting");
dte->on_read(nullptr);
return false;
}
state = status::CONNECTING;
return true;
}
@ -345,139 +344,6 @@ DECLARE_SOCK_COMMANDS(return_type name(...) )
Listener::state Listener::recv(uint8_t *data, size_t len)
{
const int MIN_MESSAGE = 6;
size_t actual_len = 0;
auto *recv_data = (char *)data;
if (data_to_recv == 0) {
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;
}
// 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);
}
auto next_comma = (char *)memchr(head_pos + head.size(), ',', MIN_MESSAGE);
if (next_comma == nullptr) {
return state::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;
}
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;
}
if (actual_len > size) {
ESP_LOGE(TAG, "TOO BIG");
return state::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;
}
read_again = (total_len > 0);
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 state::IN_PROGRESS;
}
::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;
} 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;
}
// "OK" after the data
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 state::FAIL;
}
}
if (last_pos != nullptr && (char *)data + len - last_pos > 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);
}
data_to_recv = 0;
if (read_again) {
uint64_t data_ready = 1;
write(data_ready_fd, &data_ready, sizeof(data_ready));
}
return state::OK;
}
Listener::state Listener::send(uint8_t *data, size_t len)
{
if (send_stat == 0) {
if (memchr(data, '>', len) == NULL) {
ESP_LOGE(TAG, "Missed >");
return state::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;
}
data_to_send = 0;
uint8_t ctrl_z = '\x1A';
dte->write(&ctrl_z, 1);
send_stat++;
return state::IN_PROGRESS;
}
return Listener::state::IN_PROGRESS;
}
Listener::state Listener::send(std::string_view response)
{
if (send_stat == 1) {
if (response.find("+CIPSEND:") != std::string::npos) {
send_stat = 0;
return state::OK;
}
if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to sent");
send_stat = 0;
return state::FAIL;
}
}
return Listener::state::IN_PROGRESS;
}
Listener::state Listener::connect(std::string_view response)
{
if (response.find("+CIPOPEN: 0,0") != std::string::npos) {
ESP_LOGI(TAG, "Connected!");
return state::OK;
}
if (response.find("ERROR") != std::string::npos) {
ESP_LOGE(TAG, "Failed to open");
return state::FAIL;
}
return Listener::state::IN_PROGRESS;
}
} // namespace sock_dce

View File

@ -28,7 +28,15 @@ public:
state send(std::string_view response);
state connect(std::string_view response);
void check_async_replies(std::string_view &response) const;
void start_sending(size_t len);
void start_receiving(size_t len);
bool start_connecting(std::string host, int port);
private:
void send_cmd(std::string_view command)
{
dte->write((uint8_t *) command.begin(), command.size());
}
std::array<uint8_t, size> &buffer;
size_t data_to_recv = 0;
bool read_again = false;
@ -67,31 +75,19 @@ private:
void forwarding(uint8_t *data, size_t len);
// void check_async_replies(std::string_view &response) const;
void send_cmd(std::string_view command)
{
dte->write((uint8_t *) command.begin(), command.size());
}
enum class status {
IDLE,
CONNECTING,
CONNECTION_FAILED,
SENDING,
SENDING_1,
SENDING_FAILED,
RECEIVING,
RECEIVING_1,
RECEIVING_FAILED
};
status state{status::IDLE};
static constexpr uint8_t IDLE = 1;
std::array<uint8_t, size> buffer;
Listener at{buffer, sock, data_ready_fd, dte};
size_t data_to_send = 0;
// size_t data_to_recv = 0;
bool read_again = false;
int sock {-1};
int listen_sock {-1};
int data_ready_fd {-1};