mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-19 13:32:21 +02:00
CMUX: Initial version of CMUX implementation
This commit is contained in:
@ -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.
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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_
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user