CMUX: Initial version of CMUX implementation

This commit is contained in:
David Cermak
2021-04-06 08:33:40 +02:00
parent eca6aaad33
commit 7a09175d5b
10 changed files with 184 additions and 165 deletions

View File

@ -61,7 +61,7 @@ is provided implementing these method using the uart driver.
## CMUX terminal ## CMUX terminal
The below diagram depicts the idea of using CMUX terminal mode using the CMUXedTerminal class which is a terminal The below diagram depicts the idea of using CMUX terminal mode using the CMux class which is a terminal
(it implements the basic read/write methods) interfacing arbitrary number of virtual terminals, (it implements the basic read/write methods) interfacing arbitrary number of virtual terminals,
but at the same time it is also composed of another terminal, the real terminal, which is multiplexed. but at the same time it is also composed of another terminal, the real terminal, which is multiplexed.

View File

@ -20,6 +20,8 @@
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io" #define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
using namespace esp_modem;
static const char *TAG = "pppos_example"; static const char *TAG = "pppos_example";
static EventGroupHandle_t event_group = NULL; static EventGroupHandle_t event_group = NULL;
static const int CONNECT_BIT = BIT0; static const int CONNECT_BIT = BIT0;
@ -114,7 +116,6 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
} }
static void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_config_t *dce_config, esp_netif_config_t *ppp_config);
extern "C" void app_main(void) extern "C" void app_main(void)
{ {
@ -167,7 +168,7 @@ extern "C" void app_main(void)
std::string apn = "internet"; std::string apn = "internet";
// auto device = create_generic_module(uart_dte, apn); // auto device = create_generic_module(uart_dte, apn);
auto device = create_SIM7600_module(uart_dte, apn); // auto device = create_SIM7600_module(uart_dte, apn);
// bool pin_ok = true; // bool pin_ok = true;
// if (device->read_pin(pin_ok) == command_result::OK && !pin_ok) { // if (device->read_pin(pin_ok) == command_result::OK && !pin_ok) {
// throw_if_false(device->set_pin("1234") == command_result::OK, "Cannot set PIN!"); // throw_if_false(device->set_pin("1234") == command_result::OK, "Cannot set PIN!");
@ -187,37 +188,45 @@ extern "C" void app_main(void)
// std::cout << "|" << number << "|" << std::endl; // std::cout << "|" << number << "|" << std::endl;
// std::cout << "----" << std::endl; // std::cout << "----" << std::endl;
// auto my_dce = create_generic_module_dce(uart_dte, device, esp_netif); // auto my_dce = create_generic_module_dce(uart_dte, device, esp_netif);
auto my_dce = create_SIM7600_dce_from_module(uart_dte, device, esp_netif); auto my_dce = create_SIM7600_dce(&dce_config, uart_dte, esp_netif);
my_dce->set_command_mode();
my_dce->get_module_name(number); my_dce->get_module_name(number);
std::cout << "|" << number << "|" << std::endl; std::cout << "|" << number << "|" << std::endl;
bool pin_ok = true; bool pin_ok = true;
if (my_dce->read_pin(pin_ok) == command_result::OK && !pin_ok) { if (my_dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
throw_if_false(my_dce->set_pin("1234") == command_result::OK, "Cannot set PIN!"); throw_if_false(my_dce->set_pin("1234") == command_result::OK, "Cannot set PIN!");
} }
vTaskDelay(pdMS_TO_TICKS(1000));
// return; // return;
// my_dce->set_cmux(); // my_dce->set_cmux();
// my_dce->set_cmux(); my_dce->set_mode(esp_modem::modem_mode::CMUX_MODE);
my_dce->get_imsi(number);
std::cout << "|" << number << "|" << std::endl;
// while (1) { // while (1) {
// vTaskDelay(pdMS_TO_TICKS(1000)); // vTaskDelay(pdMS_TO_TICKS(1000));
// uart_dte->write((uint8_t*)"AT+CPIN?\r", 9); // my_dce->get_imsi(number);
// std::cout << "|" << number << "|" << std::endl;
// //
// } // }
// uart_dte->send_cmux_command(2, "AT+CPIN?"); // uart_dte->send_cmux_command(2, "AT+CPIN?");
// return; // return;
my_dce->get_module_name(number); // my_dce->get_module_name(number);
my_dce->set_data_mode(); // my_dce->set_data_mode();
//
// my_dce->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) {
// std::string response((char*)data, len);
// ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data);
// std::cout << response << std::endl;
// return command_result::OK;
// }, 1000);
my_dce->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) {
std::string response((char*)data, len);
ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data);
std::cout << response << std::endl;
return command_result::OK;
}, 1000);
while (1) {
// while (1)
{
my_dce->set_data(); my_dce->set_data();
/* Config MQTT */ /* Config MQTT */
@ -230,14 +239,20 @@ extern "C" void app_main(void)
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY); xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
esp_mqtt_client_destroy(mqtt_client); esp_mqtt_client_destroy(mqtt_client);
while (1) {
vTaskDelay(pdMS_TO_TICKS(2000));
my_dce->get_imsi(number);
std::cout << "|" << number << "|" << std::endl;
}
// vTaskDelay(pdMS_TO_TICKS(20000)); // vTaskDelay(pdMS_TO_TICKS(20000));
my_dce->exit_data(); // my_dce->exit_data();
uart_dte->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) { // uart_dte->command("AT+CPIN?\r", [&](uint8_t *data, size_t len) {
std::string response((char*)data, len); // std::string response((char*)data, len);
// ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data); //// ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data);
std::cout << response << std::endl; // std::cout << response << std::endl;
return command_result::OK; // return command_result::OK;
}, 1000); // }, 1000);
} }
// ddd->send_command("AT+COPS=?\r", [&](uint8_t *data, size_t len) { // ddd->send_command("AT+COPS=?\r", [&](uint8_t *data, size_t len) {

View File

@ -15,7 +15,11 @@
#ifndef _ESP_MODEM_CMUX_HPP_ #ifndef _ESP_MODEM_CMUX_HPP_
#define _ESP_MODEM_CMUX_HPP_ #define _ESP_MODEM_CMUX_HPP_
#include "esp_modem_terminal.hpp"
namespace esp_modem { namespace esp_modem {
constexpr size_t max_terms = 2;
/** /**
* @defgroup ESP_MODEM_CMUX ESP_MODEM CMUX class * @defgroup ESP_MODEM_CMUX ESP_MODEM CMUX class
* @brief Definition of CMUX terminal * @brief Definition of CMUX terminal
@ -43,19 +47,20 @@ enum class cmux_state {
* *
* @note Implementation of CMUX protocol is experimental * @note Implementation of CMUX protocol is experimental
*/ */
class CMUXedTerminal: public Terminal { class CMuxInstance;
class CMux {
public: public:
explicit CMUXedTerminal(std::unique_ptr<Terminal> t, std::unique_ptr<uint8_t[]> b, size_t buff_size): explicit CMux(std::unique_ptr<Terminal> t, std::unique_ptr<uint8_t[]> b, size_t buff_size):
term(std::move(t)), buffer(std::move(b)) {} term(std::move(t)), buffer_size(buff_size), buffer(std::move(b)) {}
~CMUXedTerminal() override = default; ~CMux() = default;
void setup_cmux(); void init();
void set_data_cb(std::function<bool(size_t len)> f) override {} void set_read_cb(int inst, std::function<bool(uint8_t *data, size_t len)> f);
int write(uint8_t *data, size_t len) override;
int read(uint8_t *data, size_t len) override { return term->read(data, len); } int write(int i, uint8_t *data, size_t len);
void start() override;
void stop() override {}
private: private:
static bool process_cmux_recv(size_t len); std::function<bool(uint8_t *data, size_t len)> read_cb[max_terms];
void data_available(uint8_t *data, size_t len);
void send_sabm(size_t i); void send_sabm(size_t i);
std::unique_ptr<Terminal> term; std::unique_ptr<Terminal> term;
cmux_state state; cmux_state state;
@ -65,9 +70,25 @@ private:
uint8_t frame_header[6]; uint8_t frame_header[6];
size_t frame_header_offset; size_t frame_header_offset;
size_t buffer_size; size_t buffer_size;
size_t consumed;
std::unique_ptr<uint8_t[]> buffer; std::unique_ptr<uint8_t[]> buffer;
bool on_cmux(size_t len); bool on_cmux(uint8_t *data, size_t len);
static uint8_t fcs_crc(const uint8_t frame[6]);
Lock lock;
int instance;
};
class CMuxInstance: public Terminal {
public:
explicit CMuxInstance(std::shared_ptr<CMux> parent, int i): cmux(std::move(parent)), instance(i) {}
int write(uint8_t *data, size_t len) override { return cmux->write(instance, data, len); }
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override { return cmux->set_read_cb(instance, std::move(f)); }
int read(uint8_t *data, size_t len) override { return 0; }
void start() override { }
void stop() override { }
private:
std::shared_ptr<CMux> cmux;
int instance;
}; };
/** /**

View File

@ -42,8 +42,17 @@ public:
return actual_len; return actual_len;
} }
void set_data_cb(std::function<bool(size_t len)> f) { void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f)
term->set_data_cb(std::move(f)); {
on_data = std::move(f);
term->set_read_cb([this](uint8_t *data, size_t len) {
if (!data) {
auto data_to_read = std::min(len, buffer_size - consumed);
data = buffer.get();
len = term->read(data, data_to_read);
}
return on_data(data, len);
});
} }
void start() { term->start(); } void start() { term->start(); }
@ -54,7 +63,10 @@ public:
term->start(); term->start();
mode = m; mode = m;
if (m == modem_mode::DATA_MODE) { if (m == modem_mode::DATA_MODE) {
term->set_data_cb(on_data); term->set_read_cb(on_data);
if (other_term) { // if we have the other terminal, let's use it for commands
command_term = other_term.get();
}
} else if (m == modem_mode::CMUX_MODE) { } else if (m == modem_mode::CMUX_MODE) {
setup_cmux(); setup_cmux();
} }
@ -62,23 +74,32 @@ public:
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms) override; command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms) override;
void send_cmux_command(uint8_t i, const std::string &command);
private: private:
Lock lock; Lock lock;
void setup_cmux(); void setup_cmux();
// command_result command(Terminal *t, const std::string &command, got_line_cb got_line, uint32_t time_ms);
static const size_t GOT_LINE = signal_group::bit0; static const size_t GOT_LINE = signal_group::bit0;
size_t buffer_size; size_t buffer_size;
size_t consumed; size_t consumed;
std::unique_ptr<uint8_t[]> buffer; std::unique_ptr<uint8_t[]> buffer;
std::unique_ptr<Terminal> term; std::unique_ptr<Terminal> term;
Terminal *command_term;
std::unique_ptr<Terminal> other_term;
modem_mode mode; modem_mode mode;
signal_group signal; signal_group signal;
std::function<bool(size_t len)> on_data; std::function<bool(uint8_t *data, size_t len)> on_data;
}; };
//class DTE_inst: public DTE {
//public:
// DTE_inst(std::shared_ptr<DTE> parent) : DTE(t), dte(parent) {}
//private:
// std::shared_ptr<DTE> dte;
//};
} // namespace esp_modem } // namespace esp_modem
#endif // _ESP_MODEM_DTE_HPP_ #endif // _ESP_MODEM_DTE_HPP_

View File

@ -36,9 +36,10 @@ class Terminal {
public: public:
virtual ~Terminal() = default; virtual ~Terminal() = default;
virtual void set_data_cb(std::function<bool(size_t len)> f) { on_data = std::move(f); } // virtual void set_data_cb(std::function<bool(size_t len)> f) { on_data = std::move(f); }
void set_error_cb(std::function<void(terminal_error)> f) { on_error = std::move(f); } void set_error_cb(std::function<void(terminal_error)> f) { on_error = std::move(f); }
virtual void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) { on_data = std::move(f); }
virtual int write(uint8_t *data, size_t len) = 0; virtual int write(uint8_t *data, size_t len) = 0;
@ -51,7 +52,8 @@ public:
virtual size_t max_virtual_terms() { return 1; } virtual size_t max_virtual_terms() { return 1; }
protected: protected:
std::function<bool(size_t len)> on_data; // std::function<bool(size_t len)> on_data;
std::function<bool(uint8_t *data, size_t len)> on_data;
std::function<void(terminal_error)> on_error; std::function<void(terminal_error)> on_error;
}; };

View File

@ -14,16 +14,13 @@
#include <cstring> #include <cstring>
#include <unistd.h> #include <unistd.h>
#include <cxx_include/esp_modem_cmux.hpp>
#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;
/* CRC8 is the reflected CRC8/ROHC algorithm */
#define FCS_POLYNOMIAL 0xe0 /* reversed crc8 */
#define FCS_INIT_VALUE 0xFF
#define FCS_GOOD_VALUE 0xCF
#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 */
@ -54,86 +51,59 @@ using namespace esp_modem;
/* Flag sequence field between messages (start of frame) */ /* Flag sequence field between messages (start of frame) */
#define SOF_MARKER 0xF9 #define SOF_MARKER 0xF9
static uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
bool reversed) uint8_t CMux::fcs_crc(const uint8_t frame[6])
{ {
uint8_t crc = initial_value; // #define FCS_GOOD_VALUE 0xCF
size_t i, j; uint8_t crc = 0xFF; // FCS_INIT_VALUE
for (i = 0; i < len; i++) { for (int i = 1; i < 4; i++) {
crc ^= src[i]; crc ^= frame[i];
for (j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
if (reversed) {
if (crc & 0x01) { if (crc & 0x01) {
crc = (crc >> 1) ^ polynomial; crc = (crc >> 1) ^ 0xe0; // FCS_POLYNOMIAL
} else { } else {
crc >>= 1; crc >>= 1;
} }
} else {
if (crc & 0x80) {
crc = (crc << 1) ^ polynomial;
} else {
crc <<= 1;
}
}
} }
} }
return crc; return crc;
} }
void CMUXedTerminal::start() void CMux::send_sabm(size_t dlci)
{
for (size_t i = 0; i < 3; i++)
{
send_sabm(i);
usleep(100'000);
}
}
void CMUXedTerminal::send_sabm(size_t dlci)
{ {
uint8_t frame[6]; uint8_t frame[6];
frame[0] = SOF_MARKER; frame[0] = SOF_MARKER;
frame[1] = (dlci << 2) | 0x3; frame[1] = (dlci << 2) | 0x3;
frame[2] = FT_SABM | PF; frame[2] = FT_SABM | PF;
frame[3] = 1; frame[3] = 1;
frame[4] = 0xFF - crc8(&frame[1], 3, FCS_POLYNOMIAL, FCS_INIT_VALUE, true); frame[4] = 0xFF - fcs_crc(frame);
frame[5] = SOF_MARKER; frame[5] = SOF_MARKER;
term->write(frame, 6); term->write(frame, 6);
} }
bool CMUXedTerminal::process_cmux_recv(size_t len)
void CMux::data_available(uint8_t *data, size_t len)
{ {
return false; if (type == 0xFF && len > 0 && dlci > 0) {
int virtual_term = dlci - 1;
if (virtual_term < max_terms && read_cb[virtual_term])
read_cb[virtual_term](data, len);
}
} }
bool output(uint8_t *data, size_t len, std::string message) bool CMux::on_cmux(uint8_t *data, size_t actual_len)
{ {
// printf("OUTPUT: %s len=%ld \n", message.c_str(), len); if (!data) {
for (int i=0; i< len; ++i) { auto data_to_read = std::min(actual_len, buffer_size);
printf("0x%02x, ",data[i]); data = buffer.get();
actual_len = term->read(data, data_to_read);
} }
printf("----\n"); ESP_LOG_BUFFER_HEXDUMP("Received", data, actual_len, ESP_LOG_VERBOSE);
printf("%.*s", (int)len, data);
return true;
}
bool CMUXedTerminal::on_cmux(size_t len)
{
auto data_to_read = std::min(len, buffer_size);
auto data = buffer.get();
auto actual_len = term->read(data, data_to_read);
// consumed += actual_len;
ESP_LOG_BUFFER_HEXDUMP("Received", data, actual_len, ESP_LOG_INFO);
for (int i=0; i< len; ++i) {
printf("0x%02x, ",data[i]);
}
printf("\n");
uint8_t* frame = data; uint8_t* frame = data;
auto available_len = len; auto available_len = actual_len;
size_t payload_offset = 0; size_t payload_offset = 0;
size_t footer_offset = 0; size_t footer_offset = 0;
while (available_len > 0) { while (available_len > 0) {
@ -171,12 +141,12 @@ bool CMUXedTerminal::on_cmux(size_t len)
case cmux_state::PAYLOAD: case cmux_state::PAYLOAD:
if (available_len < payload_len) { // payload if (available_len < payload_len) { // payload
state = cmux_state::PAYLOAD; state = cmux_state::PAYLOAD;
output(frame, available_len, "PAYLOAD partial read"); // partial read data_available(frame, available_len); // partial read
payload_len -= available_len; payload_len -= available_len;
return false; return false;
} else { // complete } else { // complete
if (payload_len > 0) { if (payload_len > 0) {
output(&frame[0], payload_len, "PAYLOAD full read"); // rest read data_available(&frame[0], payload_len); // rest read
} }
available_len -= payload_len; available_len -= payload_len;
frame += payload_len; frame += payload_len;
@ -196,7 +166,7 @@ bool CMUXedTerminal::on_cmux(size_t len)
return true; return true;
} }
if (payload_len == 0) { if (payload_len == 0) {
output(frame_header, 0, "Null payload"); data_available(frame_header, 0); // Null payload
} }
frame += footer_offset; frame += footer_offset;
available_len -= footer_offset; available_len -= footer_offset;
@ -208,12 +178,12 @@ bool CMUXedTerminal::on_cmux(size_t len)
} }
return true; return true;
} }
void CMUXedTerminal::setup_cmux() void CMux::init()
{ {
frame_header_offset = 0; frame_header_offset = 0;
state = cmux_state::INIT; state = cmux_state::INIT;
term->set_data_cb([this](size_t len){ term->set_read_cb([this](uint8_t *data, size_t len) {
this->on_cmux(len); this->on_cmux(data, len);
return false; return false;
}); });
@ -224,51 +194,27 @@ void CMUXedTerminal::setup_cmux()
} }
} }
void DTE::setup_cmux() int CMux::write(int virtual_term, uint8_t *data, size_t len) {
{
auto original_term = std::move(term);
auto cmux_term = std::make_unique<CMUXedTerminal>(std::move(original_term), std::move(buffer), buffer_size);
buffer_size = 0;
cmux_term->setup_cmux();
term = std::move(cmux_term);
}
int i = virtual_term + 1;
void DTE::send_cmux_command(uint8_t i, const std::string& command)
{
uint8_t frame[6];
frame[0] = SOF_MARKER;
frame[1] = (i << 2) + 1;
frame[2] = FT_UIH;
frame[3] = (command.length() << 1) + 1;
frame[4] = 0xFF - crc8(&frame[1], 3, FCS_POLYNOMIAL, FCS_INIT_VALUE, true);
frame[5] = SOF_MARKER;
term->write(frame, 4);
term->write((uint8_t *)command.c_str(), command.length());
term->write(frame + 4, 2);
ESP_LOG_BUFFER_HEXDUMP("Send", frame, 4, ESP_LOG_INFO);
ESP_LOG_BUFFER_HEXDUMP("Send", (uint8_t *)command.c_str(), command.length(), ESP_LOG_INFO);
ESP_LOG_BUFFER_HEXDUMP("Send", frame+4, 2, ESP_LOG_INFO);
}
int CMUXedTerminal::write(uint8_t *data, size_t len) {
size_t i = 1;
uint8_t frame[6]; uint8_t frame[6];
frame[0] = SOF_MARKER; frame[0] = SOF_MARKER;
frame[1] = (i << 2) + 1; frame[1] = (i << 2) + 1;
frame[2] = FT_UIH; frame[2] = FT_UIH;
frame[3] = (len << 1) + 1; frame[3] = (len << 1) + 1;
frame[4] = 0xFF - crc8(&frame[1], 3, FCS_POLYNOMIAL, FCS_INIT_VALUE, true); frame[4] = 0xFF - fcs_crc(frame);
frame[5] = SOF_MARKER; frame[5] = SOF_MARKER;
term->write(frame, 4); term->write(frame, 4);
term->write(data, len); term->write(data, len);
term->write(frame + 4, 2); term->write(frame + 4, 2);
ESP_LOG_BUFFER_HEXDUMP("Send", frame, 4, ESP_LOG_INFO); ESP_LOG_BUFFER_HEXDUMP("Send", frame, 4, ESP_LOG_VERBOSE);
ESP_LOG_BUFFER_HEXDUMP("Send", data, len, ESP_LOG_INFO); ESP_LOG_BUFFER_HEXDUMP("Send", data, len, ESP_LOG_VERBOSE);
ESP_LOG_BUFFER_HEXDUMP("Send", frame+4, 2, ESP_LOG_INFO); ESP_LOG_BUFFER_HEXDUMP("Send", frame+4, 2, ESP_LOG_VERBOSE);
return 0; return 0;
} }
void CMux::set_read_cb(int inst, std::function<bool(uint8_t *, size_t)> f) {
if (inst < max_terms)
read_cb[inst] = std::move(f);
}

View File

@ -29,14 +29,12 @@ bool DCE_Mode::set(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m)
return false; return false;
netif.stop(); netif.stop();
device->set_mode(modem_mode::COMMAND_MODE); device->set_mode(modem_mode::COMMAND_MODE);
uint8_t* data; dte->set_read_cb([&](uint8_t *data, size_t len) -> bool {
dte->set_data_cb([&](size_t len) -> bool { ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_INFO);
auto actual_len = dte->read(&data, 64);
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, actual_len, ESP_LOG_INFO);
return false; return false;
}); });
netif.wait_until_ppp_exits(); netif.wait_until_ppp_exits();
dte->set_data_cb(nullptr); dte->set_read_cb(nullptr);
dte->set_mode(modem_mode::COMMAND_MODE); dte->set_mode(modem_mode::COMMAND_MODE);
mode = m; mode = m;
return true; return true;
@ -54,6 +52,10 @@ bool DCE_Mode::set(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m)
return false; return false;
device->set_mode(modem_mode::CMUX_MODE); device->set_mode(modem_mode::CMUX_MODE);
dte->set_mode(modem_mode::CMUX_MODE); dte->set_mode(modem_mode::CMUX_MODE);
// auto dte1 = create_virtual(dte, 1);
// auto dte2 = create_virtual(dte, 2);
// device->swap_dte(dte1);
// netif->swap_dte(dte2;);
mode = modem_mode::COMMAND_MODE; mode = modem_mode::COMMAND_MODE;
return true; return true;
} }

View File

@ -23,19 +23,22 @@ const int DTE_BUFFER_SIZE = 1024;
DTE::DTE(std::unique_ptr<Terminal> terminal): DTE::DTE(std::unique_ptr<Terminal> terminal):
buffer_size(DTE_BUFFER_SIZE), consumed(0), buffer_size(DTE_BUFFER_SIZE), consumed(0),
buffer(std::make_unique<uint8_t[]>(buffer_size)), buffer(std::make_unique<uint8_t[]>(buffer_size)),
term(std::move(terminal)), mode(modem_mode::UNDEF) {} term(std::move(terminal)), command_term(term.get()), other_term(nullptr),
mode(modem_mode::UNDEF) {}
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms) command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms)
{ {
Scoped<Lock> l(lock); Scoped<Lock> l(lock);
command_result res = command_result::TIMEOUT; command_result res = command_result::TIMEOUT;
term->set_data_cb([&](size_t len){ command_term->set_read_cb([&](uint8_t *data, size_t len) {
if (!data) {
auto data_to_read = std::min(len, buffer_size - consumed); auto data_to_read = std::min(len, buffer_size - consumed);
auto data = buffer.get() + consumed; data = buffer.get() + consumed;
auto actual_len = term->read(data, data_to_read); len = command_term->read(data, data_to_read);
consumed += actual_len; }
if (memchr(data, '\n', actual_len)) { consumed += len;
res = got_line(buffer.get(), consumed); if (memchr(data, '\n', len)) {
res = got_line(data, consumed);
if (res == command_result::OK || res == command_result::FAIL) { if (res == command_result::OK || res == command_result::FAIL) {
signal.set(GOT_LINE); signal.set(GOT_LINE);
return true; return true;
@ -43,12 +46,23 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
} }
return false; return false;
}); });
term->write((uint8_t *)command.c_str(), command.length()); command_term->write((uint8_t *)command.c_str(), command.length());
auto got_lf = signal.wait(GOT_LINE, time_ms); auto got_lf = signal.wait(GOT_LINE, time_ms);
if (got_lf && res == command_result::TIMEOUT) { if (got_lf && res == command_result::TIMEOUT) {
throw_if_esp_fail(ESP_ERR_INVALID_STATE); throw_if_esp_fail(ESP_ERR_INVALID_STATE);
} }
consumed = 0; consumed = 0;
term->set_data_cb(nullptr); command_term->set_read_cb(nullptr);
return res; return res;
} }
void DTE::setup_cmux()
{
auto original_term = std::move(term);
auto cmux_term = std::make_shared<CMux>(std::move(original_term), std::move(buffer), buffer_size);
buffer_size = 0;
cmux_term->init();
term = std::make_unique<CMuxInstance>(cmux_term, 0);
command_term = term.get(); // use command terminal as previously
other_term = std::make_unique<CMuxInstance>(cmux_term, 1);
}

View File

@ -53,7 +53,7 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) {
// check if PPP error events are enabled, if not, do enable the error occurred/state changed // check if PPP error events are enabled, if not, do enable the error occurred/state changed
// to notify the modem layer when switching modes // to notify the modem layer when switching modes
esp_netif_ppp_config_t ppp_config; esp_netif_ppp_config_t ppp_config;
// esp_netif_ppp_get_params(esp_netif, &ppp_config); esp_netif_ppp_get_params(esp_netif, &ppp_config);
if (!ppp_config.ppp_error_event_enabled) { if (!ppp_config.ppp_error_event_enabled) {
ppp_config.ppp_error_event_enabled = true; ppp_config.ppp_error_event_enabled = true;
esp_netif_ppp_set_params(esp_netif, &ppp_config); esp_netif_ppp_set_params(esp_netif, &ppp_config);
@ -81,10 +81,8 @@ Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
} }
void Netif::start() { void Netif::start() {
ppp_dte->set_data_cb([this](size_t len) -> bool { ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
uint8_t *data; receive(data, len);
auto actual_len = ppp_dte->read(&data, len);
receive(data, actual_len);
return false; return false;
}); });
esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr); esp_netif_action_start(driver.base.netif, nullptr, 0, nullptr);

View File

@ -149,7 +149,7 @@ public:
int read(uint8_t *data, size_t len) override; int read(uint8_t *data, size_t len) override;
void set_data_cb(std::function<bool(size_t len)> f) override { void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override {
on_data = std::move(f); on_data = std::move(f);
signal.set(TASK_PARAMS); signal.set(TASK_PARAMS);
} }
@ -185,7 +185,7 @@ std::unique_ptr<Terminal> create_uart_terminal(const esp_modem_dte_config *confi
} }
void uart_terminal::task() { void uart_terminal::task() {
std::function<bool(size_t len)> on_data_priv = nullptr; std::function<bool(uint8_t *data, size_t len)> on_data_priv = nullptr;
uart_event_t event; uart_event_t event;
size_t len; size_t len;
signal.set(TASK_INIT); signal.set(TASK_INIT);
@ -207,7 +207,7 @@ void uart_terminal::task() {
uart_get_buffered_data_len(uart.port, &len); uart_get_buffered_data_len(uart.port, &len);
// ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data); // ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data);
if (len && on_data_priv) { if (len && on_data_priv) {
if (on_data_priv(len)) { if (on_data_priv(nullptr, len)) {
on_data_priv = nullptr; on_data_priv = nullptr;
} }
} }