VFS Terminal cleanup

This commit is contained in:
David Cermak
2021-05-17 14:59:03 +02:00
parent 9f4fe3a177
commit 59c3837345
11 changed files with 268 additions and 264 deletions

View File

@ -19,6 +19,9 @@ int main()
// init the DTE // init the DTE
esp_modem_dte_config_t dte_config = { esp_modem_dte_config_t dte_config = {
.dte_buffer_size = 512, .dte_buffer_size = 512,
.task_stack_size = 1024,
.task_priority = 10,
.uart_config = { },
.vfs_config = { } .vfs_config = { }
}; };
dte_config.vfs_config.dev_name = "/dev/ttyUSB0"; dte_config.vfs_config.dev_name = "/dev/ttyUSB0";

View File

@ -18,7 +18,7 @@
#include "cxx_include/esp_modem_api.hpp" #include "cxx_include/esp_modem_api.hpp"
#include <iostream> #include <iostream>
#include "esp_https_ota.h" #include "esp_https_ota.h"
#include "esp_app_trace.h" #include "esp_vfs_dev.h"
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io" #define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
@ -130,18 +130,22 @@ extern "C" void app_main(void)
/* Configure the DTE */ /* Configure the DTE */
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
esp_modem_dte_config_t dte_config2 = { // dte_config.task_stack_size = 8192;
.dte_buffer_size = 512, dte_config.vfs_config.dev_name = "/dev/uart/1";
.vfs_config = {.port_num = UART_NUM_1, dte_config.uart_config.event_queue_size = 0;
.dev_name = "/dev/uart/1",
.rx_buffer_size = 1024, // esp_modem_dte_config_t dte_config2 = {
.tx_buffer_size = 512, // .dte_buffer_size = 512,
.baud_rate = 115200, // .vfs_config = {.port_num = UART_NUM_1,
.tx_io_num = 25, // .dev_name = "/dev/uart/1",
.rx_io_num = 26, // .rx_buffer_size = 1024,
.task_stack_size = 4096, // .tx_buffer_size = 512,
.task_prio = 5} // .baud_rate = 115200,
}; // .tx_io_num = 25,
// .rx_io_num = 26,
// .task_stack_size = 4096,
// .task_prio = 5}
// };
/* Configure the DCE */ /* Configure the DCE */
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN); esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
@ -149,13 +153,11 @@ extern "C" void app_main(void)
/* Configure the PPP netif */ /* Configure the PPP netif */
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP(); esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
dte_config.dte_buffer_size = 512; // dte_config.dte_buffer_size = 512;
dte_config.uart_config.port_num = UART_NUM_2; // dte_config.uart_config.port_num = UART_NUM_2;
auto uart_dte = create_uart_dte(&dte_config); // auto uart_dte = create_uart_dte(&dte_config);
auto uart_dte = create_vfs_dte(&dte_config);
esp_vfs_dev_uart_use_driver(dte_config.uart_config.port_num);
// auto uart_dte = create_vfs_dte(&dte_config2);
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config); esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
assert(esp_netif); assert(esp_netif);

View File

@ -53,29 +53,30 @@ struct esp_modem_uart_term_config {
int cts_io_num; /*!< CTS Pin Number */ int cts_io_num; /*!< CTS Pin Number */
int rx_buffer_size; /*!< UART RX Buffer Size */ int rx_buffer_size; /*!< UART RX Buffer Size */
int tx_buffer_size; /*!< UART TX Buffer Size */ int tx_buffer_size; /*!< UART TX Buffer Size */
int event_queue_size; /*!< UART Event Queue Size */ int event_queue_size; /*!< UART Event Queue Size, set to 0 if no event queue needed */
uint32_t event_task_stack_size; /*!< UART Event Task Stack size */
int event_task_priority; /*!< UART Event Task Priority */
}; };
/**
* @brief Resources used by VFS terminal
*
*/
typedef enum {
ESP_MODEM_VFS_IS_EXTERN = 0, /*!< External resource: internal VFS terminal takes no action to setup this */
ESP_MODEM_VFS_IS_UART, /*!< VFS uses UART: internal VFS initializes UART based on esp_modem_uart_term_config */
} esp_modem_vfs_resource_t;
struct esp_modem_vfs_term_config { struct esp_modem_vfs_term_config {
int port_num; const char* dev_name; /*!< VFS device name, e.g. /dev/uart/n */
const char* dev_name; esp_modem_vfs_resource_t resource; /*!< Underlying device which gets initialized during VFS init */
int rx_buffer_size;
int tx_buffer_size;
int baud_rate;
int tx_io_num;
int rx_io_num;
uint32_t task_stack_size;
int task_prio;
}; };
struct esp_modem_dte_config { struct esp_modem_dte_config {
size_t dte_buffer_size; size_t dte_buffer_size; /*!< DTE buffer size */
union { uint32_t task_stack_size; /*!< Terminal task stack size */
struct esp_modem_uart_term_config uart_config; int task_priority; /*!< Terminal task priority */
struct esp_modem_vfs_term_config vfs_config; struct esp_modem_uart_term_config uart_config; /*!< Configuration for UART Terminal */
}; struct esp_modem_vfs_term_config vfs_config; /*!< Configuration for VFS Terminal */
}; };
@ -86,7 +87,9 @@ struct esp_modem_dte_config {
#define ESP_MODEM_DTE_DEFAULT_CONFIG() \ #define ESP_MODEM_DTE_DEFAULT_CONFIG() \
{ \ { \
.dte_buffer_size = 512, \ .dte_buffer_size = 512, \
.uart_config = { \ .task_stack_size = 4096, \
.task_priority = 5, \
.uart_config = { \
.port_num = UART_NUM_1, \ .port_num = UART_NUM_1, \
.data_bits = UART_DATA_8_BITS, \ .data_bits = UART_DATA_8_BITS, \
.stop_bits = UART_STOP_BITS_1, \ .stop_bits = UART_STOP_BITS_1, \
@ -100,9 +103,10 @@ struct esp_modem_dte_config {
.rx_buffer_size = 4096, \ .rx_buffer_size = 4096, \
.tx_buffer_size = 512, \ .tx_buffer_size = 512, \
.event_queue_size = 30, \ .event_queue_size = 30, \
.event_task_stack_size = 4096, \ }, \
.event_task_priority = 20, \ .vfs_config = { \
} \ .dev_name = "/null", \
}\
} }
typedef struct esp_modem_dte_config esp_modem_dte_config_t; typedef struct esp_modem_dte_config esp_modem_dte_config_t;

View File

@ -19,10 +19,10 @@
struct esp_modem_dte_config; struct esp_modem_dte_config;
namespace esp_modem::terminal { namespace esp_modem {
std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config); std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config);
} // namespace esp_modem::terminal } // namespace esp_modem
#endif // _VFS_TERMINAL_HPP_ #endif // _VFS_TERMINAL_HPP_

View File

@ -39,7 +39,7 @@ std::shared_ptr<DTE> create_uart_dte(const dte_config *config) {
std::shared_ptr<DTE> create_vfs_dte(const dte_config *config) { std::shared_ptr<DTE> create_vfs_dte(const dte_config *config) {
TRY_CATCH_RET_NULL( TRY_CATCH_RET_NULL(
auto term = terminal::create_vfs_terminal(config); auto term = create_vfs_terminal(config);
return std::make_shared<DTE>(config, std::move(term)); return std::make_shared<DTE>(config, std::move(term));
) )
} }

View File

@ -15,12 +15,18 @@
#include <cstring> #include <cstring>
#include <unistd.h> #include <unistd.h>
#include <cxx_include/esp_modem_cmux.hpp> #include <cxx_include/esp_modem_cmux.hpp>
//#include "esp_app_trace.h"
#include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/esp_modem_dte.hpp"
#include "esp_log.h" #include "esp_log.h"
using namespace esp_modem; using namespace esp_modem;
/**
* @brief Define this to defragment partially received data of CMUX payload
* This is useful if upper layers expect the entire payload available
* for parsing.
*/
#define DEFRAGMENT_CMUX_PAYLOAD
#define EA 0x01 /* Extension bit */ #define EA 0x01 /* Extension bit */
#define CR 0x02 /* Command / Response */ #define CR 0x02 /* Command / Response */
#define PF 0x10 /* Poll / Final */ #define PF 0x10 /* Poll / Final */
@ -72,11 +78,11 @@ uint8_t CMux::fcs_crc(const uint8_t frame[6])
return crc; return crc;
} }
void CMux::send_sabm(size_t dlci) void CMux::send_sabm(size_t i)
{ {
uint8_t frame[6]; uint8_t frame[6];
frame[0] = SOF_MARKER; frame[0] = SOF_MARKER;
frame[1] = (dlci << 2) | 0x3; frame[1] = (i << 2) | 0x3;
frame[2] = FT_SABM | PF; frame[2] = FT_SABM | PF;
frame[3] = 1; frame[3] = 1;
frame[4] = 0xFF - fcs_crc(frame); frame[4] = 0xFF - fcs_crc(frame);
@ -90,14 +96,16 @@ void CMux::data_available(uint8_t *data, size_t len)
if (data && type == 0xFF && len > 0 && dlci > 0) { if (data && type == 0xFF && len > 0 && dlci > 0) {
int virtual_term = dlci - 1; int virtual_term = dlci - 1;
if (virtual_term < max_terms && read_cb[virtual_term]) { if (virtual_term < max_terms && read_cb[virtual_term]) {
// if (payload_start == nullptr) { // Post partial data (or defragment to post on CMUX footer)
// payload_start = data; #ifdef DEFRAGMENT_CMUX_PAYLOAD
// total_payload_size = 0; if (payload_start == nullptr) {
// } payload_start = data;
// total_payload_size += len; total_payload_size = 0;
// Post partial data (if configured) }
total_payload_size += len;
#else
read_cb[virtual_term](data, len); read_cb[virtual_term](data, len);
#endif
} }
} else if (data == nullptr && type == 0x73 && len == 0) { // notify the initial SABM command } else if (data == nullptr && type == 0x73 && len == 0) { // notify the initial SABM command
Scoped<Lock> l(lock); Scoped<Lock> l(lock);
@ -105,7 +113,9 @@ void CMux::data_available(uint8_t *data, size_t len)
} else if (data == nullptr) { } else if (data == nullptr) {
int virtual_term = dlci - 1; int virtual_term = dlci - 1;
if (virtual_term < max_terms && read_cb[virtual_term]) { if (virtual_term < max_terms && read_cb[virtual_term]) {
// read_cb[virtual_term](payload_start, total_payload_size); #ifdef DEFRAGMENT_CMUX_PAYLOAD
read_cb[virtual_term](payload_start, total_payload_size);
#endif
} }
} }
@ -114,7 +124,8 @@ void CMux::data_available(uint8_t *data, size_t len)
bool CMux::on_cmux(uint8_t *data, size_t actual_len) bool CMux::on_cmux(uint8_t *data, size_t actual_len)
{ {
if (!data) { if (!data) {
auto data_to_read = buffer_size - 155; #ifdef DEFRAGMENT_CMUX_PAYLOAD
auto data_to_read = buffer_size - 128; // keep 128 (max CMUX payload) backup buffer)
if (payload_start) { if (payload_start) {
data = payload_start + total_payload_size; data = payload_start + total_payload_size;
data_to_read = payload_len + 2; data_to_read = payload_len + 2;
@ -122,27 +133,12 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
data = buffer.get(); data = buffer.get();
} }
actual_len = term->read(data, data_to_read); actual_len = term->read(data, data_to_read);
// ESP_LOGE("Received", "data_to_read=%d, actual_len=%d, total_payload=%d", data_to_read, actual_len, total_payload_size); #else
} data = buffer.get();
#if 0 actual_len = term->read(data, buffer_size);
if (0){
static char buf[8*1024];
for (int i=0; i<actual_len; ++i)
sprintf(buf + 6*i, "0x%02x, ", data[i]);
buf[actual_len*6] = '\n';
esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, buf, actual_len*6+1, ESP_APPTRACE_TMO_INFINITE);
if (res != ESP_OK) {
ESP_LOGE("cmux", "Failed to write data to host!");
}
esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, 1000);
// usleep(1000000);
}
#endif #endif
// printf("my_data[%d] = { ", actual_len); }
// for (int i=0; i<actual_len; ++i) ESP_LOG_BUFFER_HEXDUMP("CMUX Received", data, actual_len, ESP_LOG_DEBUG);
// printf("0x%02x, ", data[i]);
// printf("};\n");
// ESP_LOG_BUFFER_HEXDUMP("Received", data, actual_len, ESP_LOG_INFO);
uint8_t* frame = data; uint8_t* frame = data;
uint8_t* recover_ptr; uint8_t* recover_ptr;
auto available_len = actual_len; auto available_len = actual_len;
@ -161,7 +157,7 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
available_len -= (recover_ptr - frame); available_len -= (recover_ptr - frame);
frame = recover_ptr; frame = recover_ptr;
state = cmux_state::INIT; state = cmux_state::INIT;
ESP_LOGW("CMUX", "Protocol recovered"); ESP_LOGI("CMUX", "Protocol recovered");
if (available_len > 1 && frame[1] == SOF_MARKER) { if (available_len > 1 && frame[1] == SOF_MARKER) {
// empty frame // empty frame
available_len -= 1; available_len -= 1;
@ -173,7 +169,7 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
return false; return false;
case cmux_state::INIT: case cmux_state::INIT:
if (frame[0] != SOF_MARKER) { if (frame[0] != SOF_MARKER) {
ESP_LOGE("CMUX", "Protocol mismatch!"); ESP_LOGW("CMUX", "Protocol mismatch: Missed leading SOF, recovering...");
state = cmux_state::RECOVER; state = cmux_state::RECOVER;
break; break;
} }
@ -211,7 +207,7 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
state = cmux_state::PAYLOAD; state = cmux_state::PAYLOAD;
break; break;
case cmux_state::PAYLOAD: case cmux_state::PAYLOAD:
ESP_LOGI("CMUX", "CMUX FR: A:%02x T:%02x L:%d available: %d", dlci, type, payload_len, available_len); ESP_LOGD("CMUX", "Payload frame: dlci:%02x type:%02x payload:%d available:%d", dlci, type, payload_len, available_len);
if (available_len < payload_len) { // payload if (available_len < payload_len) { // payload
state = cmux_state::PAYLOAD; state = cmux_state::PAYLOAD;
data_available(frame, available_len); // partial read data_available(frame, available_len); // partial read
@ -236,17 +232,18 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
footer_offset = std::min(available_len, 6 - frame_header_offset); footer_offset = std::min(available_len, 6 - frame_header_offset);
memcpy(frame_header + frame_header_offset, frame, footer_offset); memcpy(frame_header + frame_header_offset, frame, footer_offset);
if (frame_header[5] != SOF_MARKER) { if (frame_header[5] != SOF_MARKER) {
ESP_LOGE("CMUX-Footer", "Protocol mismatch! total pyaload: %d", total_payload_size); ESP_LOGW("CMUX", "Protocol mismatch: Missed trailing SOF, recovering...");
ESP_LOG_BUFFER_HEXDUMP("Data-valid", payload_start, total_payload_size, ESP_LOG_INFO); payload_start = nullptr;
ESP_LOG_BUFFER_HEXDUMP("Footer", frame-8, 16, ESP_LOG_ERROR); total_payload_size = 0;
while(1) { usleep(10000); };
abort(); // ESP_LOGE("CMUX-Footer", "Protocol mismatch! total pyaload: %d", total_payload_size);
// ESP_LOG_BUFFER_HEXDUMP("Data-valid", payload_start, total_payload_size, ESP_LOG_INFO);
// ESP_LOG_BUFFER_HEXDUMP("Footer", frame-8, 16, ESP_LOG_ERROR);
// while(1) { usleep(10000); };
// abort();
state = cmux_state::RECOVER; state = cmux_state::RECOVER;
break; break;
} }
// if (payload_len == 0) {
// data_available(frame_header, 0); // Null payload
// }
frame += footer_offset; frame += footer_offset;
available_len -= footer_offset; available_len -= footer_offset;
state = cmux_state::INIT; state = cmux_state::INIT;
@ -275,7 +272,7 @@ bool CMux::init()
{ {
int timeout = 0; int timeout = 0;
send_sabm(i); send_sabm(i);
while (1) { while (true) {
usleep(10'000); usleep(10'000);
Scoped<Lock> l(lock); Scoped<Lock> l(lock);
if (sabm_ack == i) { if (sabm_ack == i) {

View File

@ -19,22 +19,25 @@
#include "cxx_include/esp_modem_dce_module.hpp" #include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_command_library.hpp" #include "cxx_include/esp_modem_command_library.hpp"
namespace esp_modem::dce_commands { namespace esp_modem::dce_commands {
static const char *TAG = "command_lib";
command_result generic_command(CommandableIf* t, const std::string &command, command_result generic_command(CommandableIf* t, const std::string &command,
const std::list<std::string_view>& pass_phrase, const std::list<std::string_view>& pass_phrase,
const std::list<std::string_view>& fail_phrase, const std::list<std::string_view>& fail_phrase,
uint32_t timeout_ms) uint32_t timeout_ms)
{ {
printf("Command %s\n", command.c_str()); ESP_LOGI(TAG, "%s command %s\n", __func__, command.c_str());
return t->command(command, [&](uint8_t *data, size_t len) { return t->command(command, [&](uint8_t *data, size_t len) {
std::string_view response((char*)data, len); std::string_view response((char*)data, len);
printf("Response: %.*s\n", (int)response.length(), response.data()); if (data == nullptr || len == 0 || response.empty())
for (auto it : pass_phrase) return command_result::TIMEOUT;
ESP_LOGI(TAG, "Response: %.*s\n", (int)response.length(), response.data());
for (auto &it : pass_phrase)
if (response.find(it) != std::string::npos) if (response.find(it) != std::string::npos)
return command_result::OK; return command_result::OK;
for (auto it : fail_phrase) for (auto &it : fail_phrase)
if (response.find(it) != std::string::npos) if (response.find(it) != std::string::npos)
return command_result::FAIL; return command_result::FAIL;
return command_result::TIMEOUT; return command_result::TIMEOUT;
@ -46,6 +49,7 @@ static inline command_result generic_command(CommandableIf* t, const std::string
const std::string& pass_phrase, const std::string& pass_phrase,
const std::string& fail_phrase, uint32_t timeout_ms) const std::string& fail_phrase, uint32_t timeout_ms)
{ {
ESP_LOGV(TAG,"%s", __func__ );
const auto pass = std::list<std::string_view>({pass_phrase}); const auto pass = std::list<std::string_view>({pass_phrase});
const auto fail = std::list<std::string_view>({fail_phrase}); const auto fail = std::list<std::string_view>({fail_phrase});
return generic_command(t, command, pass, fail, timeout_ms); return generic_command(t, command, pass, fail, timeout_ms);
@ -53,6 +57,7 @@ static inline command_result generic_command(CommandableIf* t, const std::string
static inline command_result generic_get_string(CommandableIf* t, const std::string& command, std::string_view& output, uint32_t timeout_ms = 500) static inline command_result generic_get_string(CommandableIf* t, const std::string& command, std::string_view& output, uint32_t timeout_ms = 500)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return t->command(command, [&](uint8_t *data, size_t len) { return t->command(command, [&](uint8_t *data, size_t len) {
size_t pos = 0; size_t pos = 0;
std::string_view response((char*)data, len); std::string_view response((char*)data, len);
@ -61,7 +66,7 @@ static inline command_result generic_get_string(CommandableIf* t, const std::str
for (auto it = token.end() - 1; it > token.begin(); it--) // strip trailing CR or LF for (auto it = token.end() - 1; it > token.begin(); it--) // strip trailing CR or LF
if (*it == '\r' || *it == '\n') if (*it == '\r' || *it == '\n')
token.remove_suffix(1); token.remove_suffix(1);
printf("{%.*s}\n", static_cast<int>(token.size()), token.data()); ESP_LOGV(TAG, "Token: {%.*s}\n", static_cast<int>(token.size()), token.data());
if (token.find("OK") != std::string::npos) { if (token.find("OK") != std::string::npos) {
return command_result::OK; return command_result::OK;
@ -78,6 +83,7 @@ static inline command_result generic_get_string(CommandableIf* t, const std::str
static inline command_result generic_get_string(CommandableIf* t, const std::string& command, std::string& output, uint32_t timeout_ms = 500) static inline command_result generic_get_string(CommandableIf* t, const std::string& command, std::string& output, uint32_t timeout_ms = 500)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out; std::string_view out;
auto ret = generic_get_string(t, command, out, timeout_ms); auto ret = generic_get_string(t, command, out, timeout_ms);
if (ret == command_result::OK) if (ret == command_result::OK)
@ -88,51 +94,61 @@ static inline command_result generic_get_string(CommandableIf* t, const std::str
static inline command_result generic_command_common(CommandableIf* t, const std::string &command, uint32_t timeout = 500) static inline command_result generic_command_common(CommandableIf* t, const std::string &command, uint32_t timeout = 500)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, command, "OK", "ERROR", timeout); return generic_command(t, command, "OK", "ERROR", timeout);
} }
command_result sync(CommandableIf* t) command_result sync(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT\r"); return generic_command_common(t, "AT\r");
} }
command_result store_profile(CommandableIf* t) command_result store_profile(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT&W\r"); return generic_command_common(t, "AT&W\r");
} }
command_result power_down(CommandableIf* t) command_result power_down(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "AT+QPOWD=1\r", "POWERED DOWN", "ERROR", 1000); return generic_command(t, "AT+QPOWD=1\r", "POWERED DOWN", "ERROR", 1000);
} }
command_result power_down_sim7xxx(CommandableIf* t) command_result power_down_sim7xxx(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+CPOF\r", 1000); return generic_command_common(t, "AT+CPOF\r", 1000);
} }
command_result power_down_sim8xx(CommandableIf* t) command_result power_down_sim8xx(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "AT+CPOWD=1\r", "POWER DOWN", "ERROR", 1000); return generic_command(t, "AT+CPOWD=1\r", "POWER DOWN", "ERROR", 1000);
} }
command_result reset(CommandableIf* t) command_result reset(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "AT+CRESET\r", "PB DONE", "ERROR", 60000); return generic_command(t, "AT+CRESET\r", "PB DONE", "ERROR", 60000);
} }
command_result set_baud(CommandableIf* t, int baud) command_result set_baud(CommandableIf* t, int baud)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+IPR=" + std::to_string(baud) + "\r"); return generic_command_common(t, "AT+IPR=" + std::to_string(baud) + "\r");
} }
command_result hang_up(CommandableIf* t) command_result hang_up(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "ATH\r", 90000); return generic_command_common(t, "ATH\r", 90000);
} }
command_result get_battery_status(CommandableIf* t, int& voltage, int &bcs, int &bcl) command_result get_battery_status(CommandableIf* t, int& voltage, int &bcs, int &bcl)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out; std::string_view out;
auto ret = generic_get_string(t, "AT+CBC\r", out); auto ret = generic_get_string(t, "AT+CBC\r", out);
if (ret != command_result::OK) if (ret != command_result::OK)
@ -164,6 +180,7 @@ command_result get_battery_status(CommandableIf* t, int& voltage, int &bcs, int
command_result get_battery_status_sim7xxx(CommandableIf* t, int& voltage, int &bcs, int &bcl) command_result get_battery_status_sim7xxx(CommandableIf* t, int& voltage, int &bcs, int &bcl)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out; std::string_view out;
auto ret = generic_get_string(t, "AT+CBC\r", out); auto ret = generic_get_string(t, "AT+CBC\r", out);
if (ret != command_result::OK) if (ret != command_result::OK)
@ -188,11 +205,13 @@ command_result get_battery_status_sim7xxx(CommandableIf* t, int& voltage, int &b
command_result set_flow_control(CommandableIf* t, int dce_flow, int dte_flow) command_result set_flow_control(CommandableIf* t, int dce_flow, int dte_flow)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+IFC=" + std::to_string(dce_flow) + ", " + std::to_string(dte_flow) + "\r"); return generic_command_common(t, "AT+IFC=" + std::to_string(dce_flow) + ", " + std::to_string(dte_flow) + "\r");
} }
command_result get_operator_name(CommandableIf* t, std::string& operator_name) command_result get_operator_name(CommandableIf* t, std::string& operator_name)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out; std::string_view out;
auto ret = generic_get_string(t, "AT+COPS?\r", out, 75000); auto ret = generic_get_string(t, "AT+COPS?\r", out, 75000);
if (ret != command_result::OK) if (ret != command_result::OK)
@ -212,6 +231,7 @@ command_result get_operator_name(CommandableIf* t, std::string& operator_name)
command_result set_echo(CommandableIf* t, bool on) command_result set_echo(CommandableIf* t, bool on)
{ {
ESP_LOGV(TAG,"%s", __func__ );
if (on) if (on)
return generic_command_common(t, "ATE1\r"); return generic_command_common(t, "ATE1\r");
return generic_command_common(t, "ATE0\r"); return generic_command_common(t, "ATE0\r");
@ -219,6 +239,7 @@ command_result set_echo(CommandableIf* t, bool on)
command_result set_pdp_context(CommandableIf* t, PdpContext& pdp) command_result set_pdp_context(CommandableIf* t, PdpContext& pdp)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string pdp_command = "AT+CGDCONT=" + std::to_string(pdp.context_id) + std::string pdp_command = "AT+CGDCONT=" + std::to_string(pdp.context_id) +
",\"" + pdp.protocol_type + "\",\"" + pdp.apn + "\"\r"; ",\"" + pdp.protocol_type + "\",\"" + pdp.apn + "\"\r";
return generic_command_common(t, pdp_command); return generic_command_common(t, pdp_command);
@ -226,21 +247,25 @@ command_result set_pdp_context(CommandableIf* t, PdpContext& pdp)
command_result set_data_mode(CommandableIf* t) command_result set_data_mode(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000); return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
} }
command_result set_data_mode_sim8xx(CommandableIf* t) command_result set_data_mode_sim8xx(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000); return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
} }
command_result resume_data_mode(CommandableIf* t) command_result resume_data_mode(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "ATO\r", "CONNECT", "ERROR", 5000); return generic_command(t, "ATO\r", "CONNECT", "ERROR", 5000);
} }
command_result set_command_mode(CommandableIf* t) command_result set_command_mode(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
const auto pass = std::list<std::string_view>({"NO CARRIER", "OK"}); const auto pass = std::list<std::string_view>({"NO CARRIER", "OK"});
const auto fail = std::list<std::string_view>({"ERROR"}); const auto fail = std::list<std::string_view>({"ERROR"});
return generic_command(t, "+++", pass, fail, 5000); return generic_command(t, "+++", pass, fail, 5000);
@ -248,21 +273,25 @@ command_result set_command_mode(CommandableIf* t)
command_result get_imsi(CommandableIf* t, std::string& imsi_number) command_result get_imsi(CommandableIf* t, std::string& imsi_number)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_get_string(t, "AT+CIMI\r", imsi_number, 5000); return generic_get_string(t, "AT+CIMI\r", imsi_number, 5000);
} }
command_result get_imei(CommandableIf* t, std::string& out) command_result get_imei(CommandableIf* t, std::string& out)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_get_string(t, "AT+CGSN\r", out, 5000); return generic_get_string(t, "AT+CGSN\r", out, 5000);
} }
command_result get_module_name(CommandableIf* t, std::string& out) command_result get_module_name(CommandableIf* t, std::string& out)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_get_string(t, "AT+CGMM\r", out, 5000); return generic_get_string(t, "AT+CGMM\r", out, 5000);
} }
command_result sms_txt_mode(CommandableIf* t, bool txt = true) command_result sms_txt_mode(CommandableIf* t, bool txt = true)
{ {
ESP_LOGV(TAG,"%s", __func__ );
if (txt) if (txt)
return generic_command_common(t, "AT+CMGF=1\r"); // Text mode (default) return generic_command_common(t, "AT+CMGF=1\r"); // Text mode (default)
return generic_command_common(t, "AT+CMGF=0\r"); // PDU mode return generic_command_common(t, "AT+CMGF=0\r"); // PDU mode
@ -271,14 +300,16 @@ command_result sms_txt_mode(CommandableIf* t, bool txt = true)
command_result sms_character_set(CommandableIf* t) command_result sms_character_set(CommandableIf* t)
{ {
// Sets the default GSM character set // Sets the default GSM character set
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+CSCS=\"GSM\"\r"); return generic_command_common(t, "AT+CSCS=\"GSM\"\r");
} }
command_result send_sms(CommandableIf* t, const std::string& number, const std::string& message) command_result send_sms(CommandableIf* t, const std::string& number, const std::string& message)
{ {
ESP_LOGV(TAG,"%s", __func__ );
auto ret = t->command("AT+CMGS=\"" + number + "\"\r", [&](uint8_t *data, size_t len) { auto ret = t->command("AT+CMGS=\"" + number + "\"\r", [&](uint8_t *data, size_t len) {
std::string_view response((char*)data, len); std::string_view response((char*)data, len);
printf("%.*s", static_cast<int>(response.size()), response.data()); ESP_LOGD(TAG,"Send SMS response %.*s", static_cast<int>(response.size()), response.data());
if (response.find('>') != std::string::npos) { if (response.find('>') != std::string::npos) {
return command_result::OK; return command_result::OK;
} }
@ -292,11 +323,13 @@ command_result send_sms(CommandableIf* t, const std::string& number, const std::
command_result set_cmux(CommandableIf* t) command_result set_cmux(CommandableIf* t)
{ {
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+CMUX=0\r"); return generic_command_common(t, "AT+CMUX=0\r");
} }
command_result read_pin(CommandableIf* t, bool& pin_ok) command_result read_pin(CommandableIf* t, bool& pin_ok)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out; std::string_view out;
auto ret = generic_get_string(t, "AT+CPIN?\r", out); auto ret = generic_get_string(t, "AT+CPIN?\r", out);
if (ret != command_result::OK) if (ret != command_result::OK)
@ -316,13 +349,14 @@ command_result read_pin(CommandableIf* t, bool& pin_ok)
command_result set_pin(CommandableIf* t, const std::string& pin) command_result set_pin(CommandableIf* t, const std::string& pin)
{ {
ESP_LOGV(TAG,"%s", __func__ );
std::string set_pin_command = "AT+CPIN=" + pin + "\r"; std::string set_pin_command = "AT+CPIN=" + pin + "\r";
return generic_command_common(t, set_pin_command); return generic_command_common(t, set_pin_command);
} }
command_result get_signal_quality(CommandableIf* t, int &rssi, int &ber) command_result get_signal_quality(CommandableIf* t, int &rssi, int &ber)
{ {
printf("%s", __func__ ); ESP_LOGV(TAG,"%s", __func__ );
std::string_view out; std::string_view out;
auto ret = generic_get_string(t, "AT+CSQ\r", out); auto ret = generic_get_string(t, "AT+CSQ\r", out);
if (ret != command_result::OK) if (ret != command_result::OK)

View File

@ -39,13 +39,11 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
command_result res = command_result::TIMEOUT; command_result res = command_result::TIMEOUT;
command_term->set_read_cb([&](uint8_t *data, size_t len) { command_term->set_read_cb([&](uint8_t *data, size_t len) {
if (!data) { if (!data) {
data = buffer.get(); // + consumed; data = buffer.get();
len = command_term->read(data + consumed, buffer_size - consumed); len = command_term->read(data + consumed, buffer_size - consumed);
} else { } else {
consumed = 0; consumed = 0; // if the underlying terminal contains data, we cannot fragment
} }
// ESP_LOGD("CMD_read!", "-----");
// for (int i=0; i<len; i++) ESP_LOGV("CMD_read", "%02x",data[i] );
if (memchr(data + consumed, separator, len)) { if (memchr(data + consumed, separator, len)) {
res = got_line(data, consumed + len); res = got_line(data, consumed + len);
if (res == command_result::OK || res == command_result::FAIL) { if (res == command_result::OK || res == command_result::FAIL) {
@ -92,7 +90,6 @@ bool DTE::setup_cmux()
bool DTE::set_mode(modem_mode m) bool DTE::set_mode(modem_mode m)
{ {
term->start();
mode = m; mode = m;
if (m == modem_mode::DATA_MODE) { if (m == modem_mode::DATA_MODE) {
term->set_read_cb(on_data); term->set_read_cb(on_data);

View File

@ -12,40 +12,31 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <optional>
#include <unistd.h> #include <unistd.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
#include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/esp_modem_dte.hpp"
#include "esp_log.h" #include "esp_log.h"
#include "driver/uart.h"
#include "esp_modem_config.h" #include "esp_modem_config.h"
#include "exception_stub.hpp" #include "exception_stub.hpp"
#include "uart_resource.hpp" // In case of VFS using UART
static const char *TAG = "fs_terminal"; static const char *TAG = "fs_terminal";
namespace esp_modem::terminal { namespace esp_modem {
struct uart_resource { class Resource {
explicit uart_resource(const esp_modem_dte_config *config); public:
~uart_resource(); Resource(const esp_modem_dte_config *config);
uart_port_t port;
int fd; std::optional<uart_resource> uart;
}; };
class FdTerminal : public Terminal {
class vfs_terminal : public Terminal {
public: public:
explicit vfs_terminal(const esp_modem_dte_config *config) : explicit FdTerminal(const esp_modem_dte_config *config);
uart(config), signal(),
task_handle(config->vfs_config.task_stack_size, config->vfs_config.task_prio, this, [](void* p){
auto t = static_cast<vfs_terminal *>(p);
t->task();
Task::Delete();
}) {}
~vfs_terminal() override { ~FdTerminal() override;
stop();
}
void start() override { void start() override {
signal.set(TASK_START); signal.set(TASK_START);
@ -74,28 +65,45 @@ private:
uart_resource uart; uart_resource uart;
SignalGroup signal; SignalGroup signal;
int fd;
Task task_handle; Task task_handle;
}; };
std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config) { std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config) {
TRY_CATCH_RET_NULL( TRY_CATCH_RET_NULL(
auto term = std::make_unique<vfs_terminal>(config); auto term = std::make_unique<FdTerminal>(config);
term->start(); term->start();
return term; return term;
) )
} }
void vfs_terminal::task() { FdTerminal::FdTerminal(const esp_modem_dte_config *config) :
uart(config, nullptr), signal(), fd(-1),
task_handle(config->task_stack_size, config->task_priority, this, [](void* p){
auto t = static_cast<FdTerminal *>(p);
t->task();
Task::Delete();
if (t->fd >= 0) {
close(t->fd);
}
})
{
fd = open(config->vfs_config.dev_name, O_RDWR);
throw_if_false(fd >= 0, "Cannot open the fd");
}
void FdTerminal::task()
{
std::function<bool(uint8_t *data, size_t len)> on_data_priv = nullptr; std::function<bool(uint8_t *data, size_t len)> on_data_priv = nullptr;
// size_t len;
signal.set(TASK_INIT); signal.set(TASK_INIT);
signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY); signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY);
if (signal.is_any(TASK_STOP)) { if (signal.is_any(TASK_STOP)) {
return; // exits to the static method where the task gets deleted return; // exits to the static method where the task gets deleted
} }
// esp_vfs_dev_uart_use_driver(uart.port);
int flags = fcntl(uart.fd, F_GETFL, NULL) | O_NONBLOCK; // Set the FD to non-blocking mode
fcntl(uart.fd, F_SETFL, flags); int flags = fcntl(fd, F_GETFL, nullptr) | O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
while (signal.is_any(TASK_START)) { while (signal.is_any(TASK_START)) {
int s; int s;
@ -105,9 +113,9 @@ void vfs_terminal::task() {
.tv_usec = 0, .tv_usec = 0,
}; };
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(uart.fd, &rfds); FD_SET(fd, &rfds);
s = select(uart.fd + 1, &rfds, NULL, NULL, &tv); s = select(fd + 1, &rfds, nullptr, nullptr, &tv);
if (signal.is_any(TASK_PARAMS)) { if (signal.is_any(TASK_PARAMS)) {
on_data_priv = on_data; on_data_priv = on_data;
signal.clear(TASK_PARAMS); signal.clear(TASK_PARAMS);
@ -116,11 +124,9 @@ void vfs_terminal::task() {
if (s < 0) { if (s < 0) {
break; break;
} else if (s == 0) { } else if (s == 0) {
// ESP_LOGV(TAG, "Select exitted with timeout"); // ESP_LOGV(TAG, "Select exited with timeout");
} else { } else {
if (FD_ISSET(uart.fd, &rfds)) { if (FD_ISSET(fd, &rfds)) {
// ESP_LOGV(TAG, "FD is readable");
// uart_get_buffered_data_len(uart.port, &len);
if (on_data_priv) { if (on_data_priv) {
if (on_data_priv(nullptr, 0)) { if (on_data_priv(nullptr, 0)) {
on_data_priv = nullptr; on_data_priv = nullptr;
@ -132,23 +138,32 @@ void vfs_terminal::task() {
} }
} }
int vfs_terminal::read(uint8_t *data, size_t len) int FdTerminal::read(uint8_t *data, size_t len)
{ {
int size = ::read(uart.fd, data, len); int size = ::read(fd, data, len);
// for (int i=0; i<size; i++) ESP_LOGD(TAG, "Read: %02x",data[i] );
if (size < 0) { if (size < 0) {
ESP_LOGE(TAG, "Error occurred during read: %d", errno); if (errno != EAGAIN) {
ESP_LOGE(TAG, "Error occurred during read: %d", errno);
}
return 0; return 0;
} }
return size; return size;
} }
int vfs_terminal::write(uint8_t *data, size_t len) int FdTerminal::write(uint8_t *data, size_t len)
{ {
int size = ::write(fd, data, len);
if (size < 0) {
ESP_LOGE(TAG, "Error occurred during read: %d", errno);
return 0;
}
return size;
}
// for (int i=0; i<len; i++) ESP_LOGD(TAG, "%02x",data[i] ); FdTerminal::~FdTerminal()
return ::write(uart.fd, data, len); {
stop();
} }
} // namespace esp_modem } // namespace esp_modem

View File

@ -11,67 +11,70 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/esp_modem_dte.hpp"
#include "esp_log.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "esp_modem_config.h" #include "esp_modem_config.h"
#include "exception_stub.hpp"
#include "esp_vfs_dev.h"
#include <sys/fcntl.h>
namespace esp_modem {
static const char *TAG = "uart_terminal";
namespace esp_modem::terminal {
struct uart_resource { struct uart_resource {
explicit uart_resource(const esp_modem_dte_config *config); explicit uart_resource(const esp_modem_dte_config *config, struct QueueDefinition** event_queue);
~uart_resource(); ~uart_resource();
uart_port_t port; uart_port_t port;
int fd;
}; };
uart_resource::uart_resource(const esp_modem_dte_config *config) : uart_resource::~uart_resource()
port(-1), fd(-1)
{ {
/* Config UART */
uart_config_t uart_config = {};
uart_config.baud_rate = config->vfs_config.baud_rate;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_REF_TICK;
throw_if_esp_fail(uart_param_config(config->vfs_config.port_num, &uart_config), "config uart parameter failed");
throw_if_esp_fail(uart_set_pin(config->vfs_config.port_num, config->vfs_config.tx_io_num, config->vfs_config.rx_io_num,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE), "config uart gpio failed");
throw_if_esp_fail(uart_driver_install(config->vfs_config.port_num, config->vfs_config.rx_buffer_size, config->vfs_config.tx_buffer_size,
0, nullptr, 0), "install uart driver failed");
// throw_if_esp_fail(uart_set_rx_timeout(config->vfs_config.port_num, 1), "set rx timeout failed");
//
// throw_if_esp_fail(uart_set_rx_full_threshold(config->uart_config.port_num, 64), "config rx full threshold failed");
/* mark UART as initialized */
port = config->vfs_config.port_num;
esp_vfs_dev_uart_use_driver(port);
fd = open(config->vfs_config.dev_name, O_RDWR);
throw_if_false(fd >= 0, "Cannot open the fd");
}
uart_resource::~uart_resource() {
if (port >= UART_NUM_0 && port < UART_NUM_MAX) { if (port >= UART_NUM_0 && port < UART_NUM_MAX) {
uart_driver_delete(port); uart_driver_delete(port);
} }
} }
} // namespace esp_modem::terminal uart_resource::uart_resource(const esp_modem_dte_config *config, struct QueueDefinition** event_queue) :
port(-1)
{
esp_err_t res;
/* Config UART */
uart_config_t uart_config = {};
uart_config.baud_rate = config->uart_config.baud_rate;
uart_config.data_bits = config->uart_config.data_bits;
uart_config.parity = config->uart_config.parity;
uart_config.stop_bits = config->uart_config.stop_bits;
uart_config.flow_ctrl = (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
: UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_APB;
throw_if_esp_fail(uart_param_config(config->uart_config.port_num, &uart_config), "config uart parameter failed");
if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_pin(config->uart_config.port_num, config->uart_config.tx_io_num, config->uart_config.rx_io_num,
config->uart_config.rts_io_num, config->uart_config.cts_io_num);
} else {
res = uart_set_pin(config->uart_config.port_num, config->uart_config.tx_io_num, config->uart_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->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_hw_flow_ctrl(config->uart_config.port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
} else if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
res = uart_set_sw_flow_ctrl(config->uart_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->uart_config.port_num,
config->uart_config.rx_buffer_size, config->uart_config.tx_buffer_size,
config->uart_config.event_queue_size, config->uart_config.event_queue_size ? event_queue : nullptr,
0);
throw_if_esp_fail(res, "install uart driver failed");
throw_if_esp_fail(uart_set_rx_timeout(config->uart_config.port_num, 1), "set rx timeout failed");
throw_if_esp_fail(uart_set_rx_full_threshold(config->uart_config.port_num, 64), "config rx full threshold failed");
/* mark UART as initialized */
port = config->uart_config.port_num;
}
} // namespace esp_modem

View File

@ -25,22 +25,13 @@ static const char *TAG = "uart_terminal";
namespace esp_modem { namespace esp_modem {
/**
* @brief Uart Resource is a platform specific struct which is implemented separately
*/
struct uart_resource { struct uart_resource {
explicit uart_resource(const esp_modem_dte_config *config); explicit uart_resource(const esp_modem_dte_config *config, struct QueueDefinition** event_queue);
~uart_resource(); ~uart_resource();
uart_port_t port;
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 */
}; };
struct uart_task { struct uart_task {
@ -57,64 +48,13 @@ struct uart_task {
TaskHandle_t task_handle; /*!< UART event task handle */ TaskHandle_t task_handle; /*!< UART event task handle */
}; };
uart_resource::~uart_resource()
{
if (port >= UART_NUM_0 && port < UART_NUM_MAX) {
uart_driver_delete(port);
}
}
uart_resource::uart_resource(const esp_modem_dte_config *config) :
port(-1)
{
esp_err_t res;
/* Config UART */
uart_config_t uart_config = {};
uart_config.baud_rate = config->uart_config.baud_rate;
uart_config.data_bits = config->uart_config.data_bits;
uart_config.parity = config->uart_config.parity;
uart_config.stop_bits = config->uart_config.stop_bits;
uart_config.flow_ctrl = (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
: UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_APB;
throw_if_esp_fail(uart_param_config(config->uart_config.port_num, &uart_config), "config uart parameter failed");
if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_pin(config->uart_config.port_num, config->uart_config.tx_io_num, config->uart_config.rx_io_num,
config->uart_config.rts_io_num, config->uart_config.cts_io_num);
} else {
res = uart_set_pin(config->uart_config.port_num, config->uart_config.tx_io_num, config->uart_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->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_hw_flow_ctrl(config->uart_config.port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
} else if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
res = uart_set_sw_flow_ctrl(config->uart_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->uart_config.port_num, config->uart_config.rx_buffer_size, config->uart_config.tx_buffer_size,
config->uart_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->uart_config.port_num, 1), "set rx timeout failed");
throw_if_esp_fail(uart_set_rx_full_threshold(config->uart_config.port_num, 64), "config rx full threshold failed");
/* mark UART as initialized */
port = config->uart_config.port_num;
}
class uart_terminal : public Terminal { class uart_terminal : public Terminal {
public: public:
explicit uart_terminal(const esp_modem_dte_config *config) : explicit uart_terminal(const esp_modem_dte_config *config) :
uart(config), signal(), event_queue(), uart(config, &event_queue), signal(),
task_handle(config->uart_config.event_task_stack_size, config->uart_config.event_task_priority, this, s_task) {} task_handle(config->task_stack_size, config->task_priority, this, s_task) {}
~uart_terminal() override = default; ~uart_terminal() override = default;
@ -139,16 +79,25 @@ private:
static void s_task(void *task_param) { static void s_task(void *task_param) {
auto t = static_cast<uart_terminal *>(task_param); auto t = static_cast<uart_terminal *>(task_param);
t->task(); t->task();
vTaskDelete(NULL); vTaskDelete(nullptr);
} }
void task(); void task();
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(uart.port);
xQueueReset(event_queue);
}
static const size_t TASK_INIT = BIT0; static const size_t TASK_INIT = BIT0;
static const size_t TASK_START = BIT1; static const size_t TASK_START = BIT1;
static const size_t TASK_STOP = BIT2; static const size_t TASK_STOP = BIT2;
static const size_t TASK_PARAMS = BIT3; static const size_t TASK_PARAMS = BIT3;
QueueHandle_t event_queue;
uart_resource uart; uart_resource uart;
SignalGroup signal; SignalGroup signal;
uart_task task_handle; uart_task task_handle;
@ -172,7 +121,7 @@ void uart_terminal::task() {
return; // exits to the static method where the task gets deleted return; // exits to the static method where the task gets deleted
} }
while (signal.is_any(TASK_START)) { while (signal.is_any(TASK_START)) {
if (uart.get_event(event, 100)) { if (get_event(event, 100)) {
if (signal.is_any(TASK_PARAMS)) { if (signal.is_any(TASK_PARAMS)) {
on_data_priv = on_data; on_data_priv = on_data;
signal.clear(TASK_PARAMS); signal.clear(TASK_PARAMS);
@ -190,13 +139,13 @@ void uart_terminal::task() {
ESP_LOGW(TAG, "HW FIFO Overflow"); ESP_LOGW(TAG, "HW FIFO Overflow");
if (on_error) if (on_error)
on_error(terminal_error::BUFFER_OVERFLOW); on_error(terminal_error::BUFFER_OVERFLOW);
uart.reset_events(); reset_events();
break; break;
case UART_BUFFER_FULL: case UART_BUFFER_FULL:
ESP_LOGW(TAG, "Ring Buffer Full"); ESP_LOGW(TAG, "Ring Buffer Full");
if (on_error) if (on_error)
on_error(terminal_error::BUFFER_OVERFLOW); on_error(terminal_error::BUFFER_OVERFLOW);
uart.reset_events(); reset_events();
break; break;
case UART_BREAK: case UART_BREAK:
ESP_LOGW(TAG, "Rx Break"); ESP_LOGW(TAG, "Rx Break");
@ -224,11 +173,11 @@ void uart_terminal::task() {
int uart_terminal::read(uint8_t *data, size_t len) { int uart_terminal::read(uint8_t *data, size_t len) {
size_t length = 0; size_t length = 0;
uart_get_buffered_data_len(uart.port, &length); uart_get_buffered_data_len(uart.port, &length);
if (esp_random() < UINT32_MAX/4 && length > 32) { // if (esp_random() < UINT32_MAX/4 && length > 32) {
printf("ahoj!\n"); // printf("ahoj!\n");
length -= length/4; // length -= length/4;
} // }
size_t new_size = length/2; // size_t new_size = length/2;
length = std::min(len, length); length = std::min(len, length);
if (length > 0) { if (length > 0) {
return uart_read_bytes(uart.port, data, length, portMAX_DELAY); return uart_read_bytes(uart.port, data, length, portMAX_DELAY);