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
esp_modem_dte_config_t dte_config = {
.dte_buffer_size = 512,
.task_stack_size = 1024,
.task_priority = 10,
.uart_config = { },
.vfs_config = { }
};
dte_config.vfs_config.dev_name = "/dev/ttyUSB0";

View File

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

View File

@ -53,29 +53,30 @@ struct esp_modem_uart_term_config {
int cts_io_num; /*!< CTS Pin Number */
int rx_buffer_size; /*!< UART RX Buffer Size */
int tx_buffer_size; /*!< UART TX Buffer Size */
int event_queue_size; /*!< UART Event Queue Size */
uint32_t event_task_stack_size; /*!< UART Event Task Stack size */
int event_task_priority; /*!< UART Event Task Priority */
int event_queue_size; /*!< UART Event Queue Size, set to 0 if no event queue needed */
};
/**
* @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 {
int port_num;
const char* dev_name;
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;
const char* dev_name; /*!< VFS device name, e.g. /dev/uart/n */
esp_modem_vfs_resource_t resource; /*!< Underlying device which gets initialized during VFS init */
};
struct esp_modem_dte_config {
size_t dte_buffer_size;
union {
struct esp_modem_uart_term_config uart_config;
struct esp_modem_vfs_term_config vfs_config;
};
size_t dte_buffer_size; /*!< DTE buffer size */
uint32_t task_stack_size; /*!< Terminal task stack size */
int task_priority; /*!< Terminal task priority */
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,6 +87,8 @@ struct esp_modem_dte_config {
#define ESP_MODEM_DTE_DEFAULT_CONFIG() \
{ \
.dte_buffer_size = 512, \
.task_stack_size = 4096, \
.task_priority = 5, \
.uart_config = { \
.port_num = UART_NUM_1, \
.data_bits = UART_DATA_8_BITS, \
@ -100,9 +103,10 @@ struct esp_modem_dte_config {
.rx_buffer_size = 4096, \
.tx_buffer_size = 512, \
.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;

View File

@ -19,10 +19,10 @@
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);
} // namespace esp_modem::terminal
} // namespace esp_modem
#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) {
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));
)
}

View File

@ -15,12 +15,18 @@
#include <cstring>
#include <unistd.h>
#include <cxx_include/esp_modem_cmux.hpp>
//#include "esp_app_trace.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_log.h"
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 CR 0x02 /* Command / Response */
#define PF 0x10 /* Poll / Final */
@ -72,11 +78,11 @@ uint8_t CMux::fcs_crc(const uint8_t frame[6])
return crc;
}
void CMux::send_sabm(size_t dlci)
void CMux::send_sabm(size_t i)
{
uint8_t frame[6];
frame[0] = SOF_MARKER;
frame[1] = (dlci << 2) | 0x3;
frame[1] = (i << 2) | 0x3;
frame[2] = FT_SABM | PF;
frame[3] = 1;
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) {
int virtual_term = dlci - 1;
if (virtual_term < max_terms && read_cb[virtual_term]) {
// if (payload_start == nullptr) {
// payload_start = data;
// total_payload_size = 0;
// }
// total_payload_size += len;
// Post partial data (if configured)
// Post partial data (or defragment to post on CMUX footer)
#ifdef DEFRAGMENT_CMUX_PAYLOAD
if (payload_start == nullptr) {
payload_start = data;
total_payload_size = 0;
}
total_payload_size += len;
#else
read_cb[virtual_term](data, len);
#endif
}
} else if (data == nullptr && type == 0x73 && len == 0) { // notify the initial SABM command
Scoped<Lock> l(lock);
@ -105,7 +113,9 @@ void CMux::data_available(uint8_t *data, size_t len)
} else if (data == nullptr) {
int virtual_term = dlci - 1;
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)
{
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) {
data = payload_start + total_payload_size;
data_to_read = payload_len + 2;
@ -122,27 +133,12 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
data = buffer.get();
}
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);
}
#if 0
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);
}
#else
data = buffer.get();
actual_len = term->read(data, buffer_size);
#endif
// printf("my_data[%d] = { ", actual_len);
// for (int i=0; i<actual_len; ++i)
// printf("0x%02x, ", data[i]);
// printf("};\n");
// ESP_LOG_BUFFER_HEXDUMP("Received", data, actual_len, ESP_LOG_INFO);
}
ESP_LOG_BUFFER_HEXDUMP("CMUX Received", data, actual_len, ESP_LOG_DEBUG);
uint8_t* frame = data;
uint8_t* recover_ptr;
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);
frame = recover_ptr;
state = cmux_state::INIT;
ESP_LOGW("CMUX", "Protocol recovered");
ESP_LOGI("CMUX", "Protocol recovered");
if (available_len > 1 && frame[1] == SOF_MARKER) {
// empty frame
available_len -= 1;
@ -173,7 +169,7 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
return false;
case cmux_state::INIT:
if (frame[0] != SOF_MARKER) {
ESP_LOGE("CMUX", "Protocol mismatch!");
ESP_LOGW("CMUX", "Protocol mismatch: Missed leading SOF, recovering...");
state = cmux_state::RECOVER;
break;
}
@ -211,7 +207,7 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
state = cmux_state::PAYLOAD;
break;
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
state = cmux_state::PAYLOAD;
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);
memcpy(frame_header + frame_header_offset, frame, footer_offset);
if (frame_header[5] != SOF_MARKER) {
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();
ESP_LOGW("CMUX", "Protocol mismatch: Missed trailing SOF, recovering...");
payload_start = nullptr;
total_payload_size = 0;
// 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;
break;
}
// if (payload_len == 0) {
// data_available(frame_header, 0); // Null payload
// }
frame += footer_offset;
available_len -= footer_offset;
state = cmux_state::INIT;
@ -275,7 +272,7 @@ bool CMux::init()
{
int timeout = 0;
send_sabm(i);
while (1) {
while (true) {
usleep(10'000);
Scoped<Lock> l(lock);
if (sabm_ack == i) {

View File

@ -19,22 +19,25 @@
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_command_library.hpp"
namespace esp_modem::dce_commands {
static const char *TAG = "command_lib";
command_result generic_command(CommandableIf* t, const std::string &command,
const std::list<std::string_view>& pass_phrase,
const std::list<std::string_view>& fail_phrase,
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) {
std::string_view response((char*)data, len);
printf("Response: %.*s\n", (int)response.length(), response.data());
for (auto it : pass_phrase)
if (data == nullptr || len == 0 || response.empty())
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)
return command_result::OK;
for (auto it : fail_phrase)
for (auto &it : fail_phrase)
if (response.find(it) != std::string::npos)
return command_result::FAIL;
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& fail_phrase, uint32_t timeout_ms)
{
ESP_LOGV(TAG,"%s", __func__ );
const auto pass = std::list<std::string_view>({pass_phrase});
const auto fail = std::list<std::string_view>({fail_phrase});
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)
{
ESP_LOGV(TAG,"%s", __func__ );
return t->command(command, [&](uint8_t *data, size_t len) {
size_t pos = 0;
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
if (*it == '\r' || *it == '\n')
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) {
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)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, command, out, timeout_ms);
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)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, command, "OK", "ERROR", timeout);
}
command_result sync(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT\r");
}
command_result store_profile(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT&W\r");
}
command_result power_down(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "AT+QPOWD=1\r", "POWERED DOWN", "ERROR", 1000);
}
command_result power_down_sim7xxx(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+CPOF\r", 1000);
}
command_result power_down_sim8xx(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "AT+CPOWD=1\r", "POWER DOWN", "ERROR", 1000);
}
command_result reset(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "AT+CRESET\r", "PB DONE", "ERROR", 60000);
}
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");
}
command_result hang_up(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "ATH\r", 90000);
}
command_result get_battery_status(CommandableIf* t, int& voltage, int &bcs, int &bcl)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, "AT+CBC\r", out);
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)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, "AT+CBC\r", out);
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)
{
ESP_LOGV(TAG,"%s", __func__ );
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)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, "AT+COPS?\r", out, 75000);
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)
{
ESP_LOGV(TAG,"%s", __func__ );
if (on)
return generic_command_common(t, "ATE1\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)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string pdp_command = "AT+CGDCONT=" + std::to_string(pdp.context_id) +
",\"" + pdp.protocol_type + "\",\"" + pdp.apn + "\"\r";
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)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
}
command_result set_data_mode_sim8xx(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
}
command_result resume_data_mode(CommandableIf* t)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command(t, "ATO\r", "CONNECT", "ERROR", 5000);
}
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 fail = std::list<std::string_view>({"ERROR"});
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)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_get_string(t, "AT+CIMI\r", imsi_number, 5000);
}
command_result get_imei(CommandableIf* t, std::string& out)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_get_string(t, "AT+CGSN\r", out, 5000);
}
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);
}
command_result sms_txt_mode(CommandableIf* t, bool txt = true)
{
ESP_LOGV(TAG,"%s", __func__ );
if (txt)
return generic_command_common(t, "AT+CMGF=1\r"); // Text mode (default)
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)
{
// Sets the default GSM character set
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+CSCS=\"GSM\"\r");
}
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) {
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) {
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)
{
ESP_LOGV(TAG,"%s", __func__ );
return generic_command_common(t, "AT+CMUX=0\r");
}
command_result read_pin(CommandableIf* t, bool& pin_ok)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, "AT+CPIN?\r", out);
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)
{
ESP_LOGV(TAG,"%s", __func__ );
std::string set_pin_command = "AT+CPIN=" + pin + "\r";
return generic_command_common(t, set_pin_command);
}
command_result get_signal_quality(CommandableIf* t, int &rssi, int &ber)
{
printf("%s", __func__ );
ESP_LOGV(TAG,"%s", __func__ );
std::string_view out;
auto ret = generic_get_string(t, "AT+CSQ\r", out);
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_term->set_read_cb([&](uint8_t *data, size_t len) {
if (!data) {
data = buffer.get(); // + consumed;
data = buffer.get();
len = command_term->read(data + consumed, buffer_size - consumed);
} 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)) {
res = got_line(data, consumed + len);
if (res == command_result::OK || res == command_result::FAIL) {
@ -92,7 +90,6 @@ bool DTE::setup_cmux()
bool DTE::set_mode(modem_mode m)
{
term->start();
mode = m;
if (m == modem_mode::DATA_MODE) {
term->set_read_cb(on_data);

View File

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

View File

@ -11,67 +11,70 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_log.h"
#include "driver/uart.h"
#include "esp_modem_config.h"
#include "exception_stub.hpp"
#include "esp_vfs_dev.h"
#include <sys/fcntl.h>
static const char *TAG = "uart_terminal";
namespace esp_modem::terminal {
namespace esp_modem {
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_port_t port;
int fd;
};
uart_resource::uart_resource(const esp_modem_dte_config *config) :
port(-1), fd(-1)
uart_resource::~uart_resource()
{
/* 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) {
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 {
/**
* @brief Uart Resource is a platform specific struct which is implemented separately
*/
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();
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 */
uart_port_t port;
};
struct uart_task {
@ -57,64 +48,13 @@ struct uart_task {
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 {
public:
explicit uart_terminal(const esp_modem_dte_config *config) :
uart(config), signal(),
task_handle(config->uart_config.event_task_stack_size, config->uart_config.event_task_priority, this, s_task) {}
event_queue(), uart(config, &event_queue), signal(),
task_handle(config->task_stack_size, config->task_priority, this, s_task) {}
~uart_terminal() override = default;
@ -139,16 +79,25 @@ private:
static void s_task(void *task_param) {
auto t = static_cast<uart_terminal *>(task_param);
t->task();
vTaskDelete(NULL);
vTaskDelete(nullptr);
}
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_START = BIT1;
static const size_t TASK_STOP = BIT2;
static const size_t TASK_PARAMS = BIT3;
QueueHandle_t event_queue;
uart_resource uart;
SignalGroup signal;
uart_task task_handle;
@ -172,7 +121,7 @@ void uart_terminal::task() {
return; // exits to the static method where the task gets deleted
}
while (signal.is_any(TASK_START)) {
if (uart.get_event(event, 100)) {
if (get_event(event, 100)) {
if (signal.is_any(TASK_PARAMS)) {
on_data_priv = on_data;
signal.clear(TASK_PARAMS);
@ -190,13 +139,13 @@ void uart_terminal::task() {
ESP_LOGW(TAG, "HW FIFO Overflow");
if (on_error)
on_error(terminal_error::BUFFER_OVERFLOW);
uart.reset_events();
reset_events();
break;
case UART_BUFFER_FULL:
ESP_LOGW(TAG, "Ring Buffer Full");
if (on_error)
on_error(terminal_error::BUFFER_OVERFLOW);
uart.reset_events();
reset_events();
break;
case UART_BREAK:
ESP_LOGW(TAG, "Rx Break");
@ -224,11 +173,11 @@ void uart_terminal::task() {
int uart_terminal::read(uint8_t *data, size_t len) {
size_t length = 0;
uart_get_buffered_data_len(uart.port, &length);
if (esp_random() < UINT32_MAX/4 && length > 32) {
printf("ahoj!\n");
length -= length/4;
}
size_t new_size = length/2;
// if (esp_random() < UINT32_MAX/4 && length > 32) {
// printf("ahoj!\n");
// length -= length/4;
// }
// size_t new_size = length/2;
length = std::min(len, length);
if (length > 0) {
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);