Reworded DCE/DTE modes and switching

This commit is contained in:
David Cermak
2021-03-03 20:35:08 +01:00
parent 00662fcaea
commit 25f5541199
20 changed files with 677 additions and 408 deletions

View File

@ -10,7 +10,12 @@ set(srcs "src/esp_modem.c"
"src/esp_bg96.c"
"src/esp_modem_dte.cpp"
"src/ppp_netif.cpp"
"src/esp_modem_commands.cpp")
"src/esp_modem_commands.cpp"
"src/esp_modem_api.cpp"
"src/esp_modem_dce.cpp"
"src/esp_modem_device.cpp"
"src/esp_modem_device_factory.cpp"
"src/esp_modem_uart.cpp")
set(include_dirs "include")

View File

@ -17,8 +17,9 @@
#include "esp_log.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/uart_terminal.hpp"
#include "cxx_include/esp_modem_api.hpp"
#define BROKER_URL "mqtt://mqtt.eclipse.org"
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
static const char *TAG = "pppos_example";
static EventGroupHandle_t event_group = NULL;
@ -135,9 +136,11 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
int msg_id;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
ESP_LOGE(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(event_group, GOT_DATA_BIT);
//
// msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0);
// ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
@ -262,36 +265,58 @@ static void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_con
// dte_config->line_buffer_size = 1000000;
uint8_t data[32] = {};
int actual_len = 0;
auto ddd = create_dte(dte_config);
ddd->set_mode(dte_mode::UNDEF);
ddd->send_command("AT+CPIN?\r", [&](uint8_t *data, size_t len) {
auto uart_dte = create_uart_dte(dte_config);
uart_dte->set_mode(dte_mode::UNDEF);
uart_dte->command("+++", [&](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 true;
return command_result::OK;
}, 1000);
// ddd->send_command("AT+CPIN=1234\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);
// ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data);
// std::cout << response << std::endl;
// return true;
// return command_result::OK;
// }, 1000);
// uart_dte->command("AT+CPIN=1234\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);
//
// return;
esp_netif_t *esp_netif = esp_netif_new(ppp_config);
assert(esp_netif);
auto my_dce = create_dce(ddd, esp_netif);
std::string apn = "internet";
auto device = create_device(uart_dte, apn);
auto my_dce = create_dce(uart_dte, device, esp_netif);
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 true;
return command_result::OK;
}, 1000);
my_dce->set_data();
/* Config MQTT */
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
esp_mqtt_client_config_t mqtt_config = { };
mqtt_config.uri = BROKER_URL;
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
esp_mqtt_client_destroy(mqtt_client);
// vTaskDelay(pdMS_TO_TICKS(20000));
my_dce->exit_data();
// ddd->send_command("AT+COPS=?\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);
@ -312,6 +337,13 @@ static void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_con
// vTaskDelay(pdMS_TO_TICKS(1000));
// len = uart->read(data, 32);
ESP_LOGI(TAG, "len=%d data %s", actual_len, (char*)data);
uart_dte->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);
return;
/* create dce object */

View File

@ -0,0 +1,14 @@
#pragma once
#include <memory>
#include "cxx_include/esp_modem_dce.hpp"
#include "cxx_include/esp_modem_device_factory.hpp"
class DTE;
struct dte_config;
typedef struct esp_netif_obj esp_netif_t;
std::shared_ptr<DTE> create_uart_dte(const dte_config *config);
std::unique_ptr<DCE> create_dce(const std::shared_ptr<DTE>& dte, const std::shared_ptr<DeviceIf>& dev, esp_netif_t *netif);

View File

@ -5,12 +5,81 @@
#ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_COMMANDS_HPP
#define SIMPLE_CXX_CLIENT_ESP_MODEM_COMMANDS_HPP
#include "esp_err.h"
#include "esp_modem_dte.hpp"
//#include "esp_modem_dce_commands.hpp"
enum class command_result;
struct PdpContext {
PdpContext(std::string& apn): context_id(1), protocol_type("IP"), apn(apn) {}
size_t context_id;
std::string protocol_type;
std::string apn;
};
#include <iostream>
namespace esp_modem {
namespace dce_commands {
template <typename T> esp_err_t sync(T t);
template <typename T> static inline command_result generic_command(T t, const std::string& command,
const std::string& pass_phrase,
const std::string& fail_phrase, uint32_t timeout_ms)
{
std::cout << command << std::endl;
return t->command(command.c_str(), [&](uint8_t *data, size_t len) {
std::string response((char*)data, len);
std::cout << response << std::endl;
if (response.find(pass_phrase) != std::string::npos) {
return command_result::OK;
} else if (response.find(fail_phrase) != std::string::npos) {
return command_result::FAIL;
}
return command_result::TIMEOUT;
}, timeout_ms);
}
template <typename T> static inline command_result generic_command_common(T t, std::string command)
{
return generic_command(t, command, "OK", "ERROR", 500);
}
template <typename T> command_result sync(T t)
{
return generic_command_common(t, "AT\r");
}
template <typename T> command_result set_echo(T t, bool on)
{
if (on)
return generic_command_common(t, "ATE1\r");
return generic_command_common(t, "ATE0\r");
}
template <typename T> command_result set_pdp_context(T t, PdpContext& pdp)
{
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);
}
template <typename T> command_result set_data_mode(T t)
{
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
}
template <typename T> command_result resume_data_mode(T t)
{
return generic_command(t, "ATO\r", "CONNECT", "ERROR", 5000);
}
template <typename T> command_result set_command_mode(T t)
{
return generic_command(t, "+++", "OK", "ERROR", 50000);
}
} // dce_commands
} // esp_modem

View File

@ -0,0 +1,32 @@
#pragma once
#include "cxx_include/esp_modem_dce_commands_if.hpp"
class DCE {
public:
explicit DCE(const std::shared_ptr<DTE>& d, std::shared_ptr<DeviceIf> device, esp_netif_t * netif);
void set_data() {
// command("AT+CGDCONT=1,\"IP\",\"internet\"\r", [&](uint8_t *data, size_t len) {
// return command_result::OK;
// }, 1000);
// command("ATD*99***1#\r", [&](uint8_t *data, size_t len) {
// return command_result::OK;
// }, 1000);
device->setup_data_mode();
device->set_mode(dte_mode::DATA_MODE);
dce_dte->set_mode(dte_mode::DATA_MODE);
ppp_netif.start();
}
void exit_data() {
ppp_netif.stop();
device->set_mode(dte_mode::COMMAND_MODE);
ppp_netif.wait_until_ppp_exits();
dce_dte->set_mode(dte_mode::COMMAND_MODE);
}
command_result command(const std::string& command, got_line_cb got_line, uint32_t time_ms) {
return dce_dte->command(command, got_line, time_ms);
}
private:
std::shared_ptr<DTE> dce_dte;
std::shared_ptr<DeviceIf> device;
ppp ppp_netif;
};

View File

@ -0,0 +1,28 @@
#pragma once
#include "cxx_include/esp_modem_dce_commands_if.hpp"
#include "cxx_include/esp_modem_commands.hpp"
#include <memory>
#include <utility>
enum class command_result;
class DTE;
class Device: public DeviceIf {
public:
explicit Device(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
dte(std::move(dte)), pdp(std::move(pdp)) {}
bool setup_data_mode() override;
bool set_mode(dte_mode mode) override;
command_result set_echo(bool on) { return esp_modem::dce_commands::set_echo(dte, on); }
command_result set_data_mode() { return esp_modem::dce_commands::set_data_mode(dte); }
command_result resume_data_mode() { return esp_modem::dce_commands::resume_data_mode(dte); }
command_result set_pdp_context(PdpContext& pdp_context) { return esp_modem::dce_commands::set_pdp_context(dte.get(), pdp_context); }
command_result set_command_mode() { return esp_modem::dce_commands::set_command_mode(dte); }
private:
std::shared_ptr<DTE> dte;
std::unique_ptr<PdpContext> pdp;
};

View File

@ -0,0 +1,9 @@
#pragma once
enum class dte_mode;
class DeviceIf {
public:
virtual bool setup_data_mode() = 0;
virtual bool set_mode(dte_mode mode) = 0;
};

View File

@ -0,0 +1,3 @@
#pragma once
std::shared_ptr<DeviceIf> create_device(const std::shared_ptr<DTE>& dte, std::string &apn);

View File

@ -51,19 +51,21 @@ enum class dte_mode {
DATA_MODE
};
const int DTE_BUFFER_SIZE = 1024;
struct dte_data {
uint8_t *data;
size_t len;
enum class command_result {
OK,
FAIL,
TIMEOUT
};
typedef std::function<bool(uint8_t *data, size_t len)> got_line_cb;
const int DTE_BUFFER_SIZE = 1024;
class dte {
typedef std::function<command_result(uint8_t *data, size_t len)> got_line_cb;
class DTE {
public:
explicit dte(std::unique_ptr<terminal> t);
~dte() = default;
explicit DTE(std::unique_ptr<terminal> t);
~DTE() = default;
// void set_line_cb(got_line f) { on_line_cb = std::move(f); }
int write(uint8_t *data, size_t len) { return term->write(data, len); }
int read(uint8_t **d, size_t len) {
@ -83,7 +85,7 @@ public:
term->set_data_cb(on_data);
}
}
bool send_command(const std::string& command, got_line_cb got_line, uint32_t time_ms);
command_result command(const std::string& command, got_line_cb got_line, uint32_t time_ms);
private:
const size_t GOT_LINE = BIT0;
@ -98,27 +100,7 @@ private:
};
class dce {
public:
explicit dce(std::shared_ptr<dte> d, esp_netif_t * netif);
void set_data() {
command("AT+CGDCONT=1,\"IP\",\"internet\"\r", [&](uint8_t *data, size_t len) {
return true;
}, 1000);
command("ATD*99***1#\r", [&](uint8_t *data, size_t len) {
return true;
}, 1000);
dce_dte->set_mode(dte_mode::DATA_MODE);
ppp_netif.start();
}
bool command(const std::string& command, got_line_cb got_line, uint32_t time_ms) {
return dce_dte->send_command(command, got_line, time_ms);
}
private:
std::shared_ptr<dte> dce_dte;
ppp ppp_netif;
};

View File

@ -0,0 +1,10 @@
//
// Created by david on 3/3/21.
//
#ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_UART_TERMINAL_HPP
#define SIMPLE_CXX_CLIENT_ESP_MODEM_UART_TERMINAL_HPP
#endif //SIMPLE_CXX_CLIENT_ESP_MODEM_UART_TERMINAL_HPP

View File

@ -6,26 +6,33 @@
#define SIMPLE_CXX_CLIENT_PPP_NETIF_HPP
#include "esp_netif.h"
#include "cxx_include/terminal_objects.hpp"
class dte;
class DTE;
//struct ppp_netif_driver;
struct ppp_netif_driver {
esp_netif_driver_base_t base;
dte *e;
DTE *e;
};
class ppp {
public:
explicit ppp(std::shared_ptr<dte> e, esp_netif_t *netif);
explicit ppp(std::shared_ptr<DTE> e, esp_netif_t *netif);
void start();
void notify_ppp_exit() { signal.set(PPP_EXIT); }
void wait_until_ppp_exits() { signal.wait(PPP_EXIT, 50000); }
void stop();
private:
void receive(uint8_t *data, size_t len) const;
std::shared_ptr<dte> ppp_dte;
std::shared_ptr<DTE> ppp_dte;
esp_netif_t *netif;
struct ppp_netif_driver driver;
signal_group signal;
const size_t PPP_EXIT = BIT0;
};

View File

@ -6,15 +6,12 @@
#define SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_dte_config.h"
std::unique_ptr<terminal> create_uart_terminal(const struct dte_config *config);
class dte;
struct dte_config;
std::shared_ptr<dte> create_dte(const struct dte_config *config);
std::unique_ptr<terminal> create_uart_terminal(const dte_config *config);
std::unique_ptr<dce> create_dce(const std::shared_ptr<dte>& e, esp_netif_t *netif);
#endif //SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP

View File

@ -0,0 +1,44 @@
//
// Created by david on 3/3/21.
//
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/uart_terminal.hpp"
#include "esp_log.h"
#include "cxx_include/esp_modem_api.hpp"
static const char *TAG = "dce_factory";
struct PdpContext;
std::shared_ptr<DTE> create_uart_dte(const dte_config *config)
{
try {
// auto term = std::make_unique<dte>(std::make_unique<uart_terminal>(config));
auto term = create_uart_terminal(config);
return std::make_shared<DTE>(std::move(term));
} catch (std::bad_alloc& e) {
ESP_LOGE(TAG, "Out of memory");
return nullptr;
} catch (esp_err_exception& e) {
esp_err_t err = e.get_err_t();
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
ESP_LOGE(TAG, "%s", e.what());
return nullptr;
}
}
std::unique_ptr<DCE> create_dce(const std::shared_ptr<DTE>& dte, const std::shared_ptr<DeviceIf>& dev, esp_netif_t *netif)
{
try {
return std::make_unique<DCE>(dte, dev, netif);
} catch (std::bad_alloc& e) {
ESP_LOGE(TAG, "Out of memory");
return nullptr;
} catch (esp_err_exception& e) {
esp_err_t err = e.get_err_t();
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
ESP_LOGE(TAG, "%s", e.what());
return nullptr;
}
}

View File

@ -5,18 +5,61 @@
namespace esp_modem::dce_commands {
template <typename T> esp_err_t sync(T t)
{
return t->send_command("AT\r", [&](uint8_t *data, size_t len) {
std::string response((char*)data, len);
if (response.find("OK") != std::string::npos) {
return ESP_OK;
} else if (response.find("ERROR") != std::string::npos) {
return ESP_FAIL;
}
return ESP_ERR_INVALID_STATE;
}, 1000);
}
//template <typename T> static inline command_result generic_command(T t, std::string command,
// std::string pass_phrase, std::string fail_phrase, uint32_t timeout_ms)
//{
// return t->command(command.c_str(), [&](uint8_t *data, size_t len) {
// std::string response((char*)data, len);
// if (response.find(pass_phrase) != std::string::npos) {
// return command_result::OK;
// } else if (response.find(fail_phrase) != std::string::npos) {
// return command_result::FAIL;
// }
// return command_result::TIMEOUT;
// }, timeout_ms);
//}
//
//template <typename T> static inline command_result generic_command_common(T t, std::string command)
//{
// return generic_command(t, command, "OK", "ERROR", 500);
//}
//
//template <typename T> command_result sync(T t)
//{
// return t->command("AT\r", [&](uint8_t *data, size_t len) {
// std::string response((char*)data, len);
// if (response.find("OK") != std::string::npos) {
// return command_result::OK;
// } else if (response.find("ERROR") != std::string::npos) {
// return command_result::FAIL;
// }
// return command_result::TIMEOUT;
// }, 1000);
//}
//template <typename T> command_result set_echo(T t, bool on) { return command_result::OK; }
//template <typename T> command_result set_echo(T* t, bool on)
//{
// if (on)
// return generic_command_common(t, "ATE1\r");
// return generic_command_common(t, "ATE0\r");
//}
//
//template <typename T> command_result set_data_mode(T t)
//{
// return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
//}
//
//template <typename T> command_result set_pdp_context(T t, PdpContext& pdp_context)
//{
// return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
//}
}
@ -25,7 +68,7 @@ namespace esp_modem {
template <class T>
class generic_dce {
public:
explicit generic_dce(std::shared_ptr<dte> e) : dce_dte(std::move(e)) {}
explicit generic_dce(std::shared_ptr<DTE> e) : dce_dte(std::move(e)) {}
esp_err_t sync() { return dce_commands::sync(dce_dte); }

View File

@ -0,0 +1,11 @@
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce.hpp"
#include <string.h>
#include <utility>
#include "esp_log.h"
DCE::DCE(const std::shared_ptr<DTE>& dte, std::shared_ptr<DeviceIf> device, esp_netif_t * netif):
dce_dte(dte), device(std::move(device)), ppp_netif(dte, netif)
{ }

View File

@ -0,0 +1,30 @@
//
// Created by david on 3/3/21.
//
#include "cxx_include/esp_modem_dce_commands.hpp"
#include "cxx_include/esp_modem_dte.hpp"
bool Device::setup_data_mode() {
if (set_echo(false) != command_result::OK)
return false;
if (set_pdp_context(*pdp) != command_result::OK)
return false;
// if (set_data_mode() != command_result::OK)
// return false;
return true;
}
bool Device::set_mode(dte_mode mode) {
if (mode == dte_mode::DATA_MODE) {
if (set_data_mode() != command_result::OK)
return resume_data_mode() == command_result::OK;
return true;
} else if (mode == dte_mode::COMMAND_MODE) {
return set_command_mode() == command_result::OK;
}
return true;
}

View File

@ -0,0 +1,9 @@
#include "cxx_include/esp_modem_dce_commands.hpp"
#include "cxx_include/esp_modem_dte.hpp"
std::shared_ptr<DeviceIf> create_device(const std::shared_ptr<DTE>& dte, std::string &apn)
{
auto pdp = std::make_unique<PdpContext>(apn);
return std::make_shared<Device>(dte, std::move(pdp));
}

View File

@ -1,334 +1,16 @@
//
// Created by david on 2/24/21.
//
#include "cxx_include/esp_modem_dte.hpp"
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_modem.h"
#include "esp_modem_dce.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_modem_internal.h"
#include "esp_modem_dte_internal.h"
#include "esp_modem_dte_config.h"
#include <memory>
#include <utility>
#define ESP_MODEM_EVENT_QUEUE_SIZE (16)
#define MIN_PATTERN_INTERVAL (9)
#define MIN_POST_IDLE (0)
#define MIN_PRE_IDLE (0)
DTE::DTE(std::unique_ptr<terminal> terminal):
buffer_size(DTE_BUFFER_SIZE), consumed(0),
buffer(std::make_unique<uint8_t[]>(buffer_size)),
term(std::move(terminal)), mode(dte_mode::UNDEF) {}
static const char *TAG = "dte_uart";
//class uart_terminal;
//class dte {
//public:
// esp_err_t init(std::unique_ptr<terminal> t);
//
//private:
// std::unique_ptr<terminal> m_terminal;
//
//};
struct uart_task {
explicit uart_task(size_t stack_size, size_t priority, void* task_param, TaskFunction_t task_function):
task_handle(nullptr)
{
BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle);
throw_if_false(ret == pdTRUE, "create uart event task failed");
}
~uart_task()
{
if (task_handle) vTaskDelete(task_handle);
}
TaskHandle_t task_handle; /*!< UART event task handle */
};
struct uart_event_loop {
explicit uart_event_loop(): event_loop_hdl(nullptr)
{
esp_event_loop_args_t loop_args = {};
loop_args.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE;
loop_args.task_name = nullptr;
throw_if_esp_fail(esp_event_loop_create(&loop_args, &event_loop_hdl), "create event loop failed");
}
void run() { esp_event_loop_run(event_loop_hdl, pdMS_TO_TICKS(0)); }
~uart_event_loop() { if (event_loop_hdl) esp_event_loop_delete(event_loop_hdl); }
esp_event_loop_handle_t event_loop_hdl;
};
struct uart_resource {
explicit uart_resource(const struct dte_config *config);
~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 */
// esp_modem_on_receive receive_cb; /*!< ptr to data reception */
// void *receive_cb_ctx; /*!< ptr to rx fn context data */
int line_buffer_size; /*!< line buffer size in command mode */
int pattern_queue_size; /*!< UART pattern queue size */
};
class uart_terminal: public terminal {
public:
explicit uart_terminal(const struct dte_config *config):
uart(config), event_loop(), signal(),
task_handle(config->event_task_stack_size, config->event_task_priority, this, s_task) {}
~uart_terminal() override = default;
void start() override
{
signal.set(TASK_START);
}
void stop() override
{
signal.set(TASK_STOP);
}
// { ESP_LOGE(TAG, "uart_terminal destruct"); }
int write(uint8_t *data, size_t len) override;
int read(uint8_t *data, size_t len) override;
private:
static void s_task(void * task_param)
{
auto t = static_cast<uart_terminal*>(task_param);
t->task();
vTaskDelete(NULL);
}
void task();
const size_t TASK_INIT = BIT0;
const size_t TASK_START = BIT1;
const size_t TASK_STOP = BIT2;
uart_resource uart;
uart_event_loop event_loop;
signal_group signal;
uart_task task_handle;
};
uart_resource::~uart_resource()
{
if (port >= UART_NUM_0 && port < UART_NUM_MAX) {
uart_driver_delete(port);
}
}
uart_resource::uart_resource(const struct dte_config *config):
port(-1)
// buffer(std::make_unique<uint8_t[]>(config->line_buffer_size))
{
esp_err_t res;
line_buffer_size = config->line_buffer_size;
/* TODO: Bind methods */
/* Config UART */
uart_config_t uart_config = {};
uart_config.baud_rate = config->baud_rate;
uart_config.data_bits = config->data_bits;
uart_config.parity = config->parity;
uart_config.stop_bits = config->stop_bits;
uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
: UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_REF_TICK;
throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
config->rts_io_num, config->cts_io_num);
} else {
res = uart_set_pin(config->port_num, config->tx_io_num, 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->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
res = uart_set_sw_flow_ctrl(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->port_num, config->rx_buffer_size, config->tx_buffer_size,
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->port_num, 1), "set rx timeout failed");
/* Set pattern interrupt, used to detect the end of a line. */
// res = uart_enable_pattern_det_baud_intr(config->port_num, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
/* Set pattern queue size */
// pattern_queue_size = config->pattern_queue_size;
// res |= uart_pattern_queue_reset(config->port_num, config->pattern_queue_size);
/* Starting in command mode -> explicitly disable RX interrupt */
// uart_disable_rx_intr(config->port_num);
uart_set_rx_full_threshold(config->port_num, 64);
throw_if_esp_fail(res, "config uart pattern failed");
/* mark UART as initialized */
port = config->port_num;
}
std::unique_ptr<terminal> create_uart_terminal(const struct dte_config *config)
{
try {
auto term = std::make_unique<uart_terminal>(config);
term->start();
return term;
} catch (std::bad_alloc& e) {
ESP_LOGE(TAG, "Out of memory");
return nullptr;
} catch (esp_err_exception& e) {
esp_err_t err = e.get_err_t();
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
ESP_LOGE(TAG, "%s", e.what());
return nullptr;
}
}
std::shared_ptr<dte> create_dte(const struct dte_config *config)
{
try {
// auto term = std::make_unique<dte>(std::make_unique<uart_terminal>(config));
auto term = std::make_shared<dte>(std::make_unique<uart_terminal>(config));
return term;
} catch (std::bad_alloc& e) {
ESP_LOGE(TAG, "Out of memory");
return nullptr;
} catch (esp_err_exception& e) {
esp_err_t err = e.get_err_t();
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
ESP_LOGE(TAG, "%s", e.what());
return nullptr;
}
}
std::unique_ptr<dce> create_dce(const std::shared_ptr<dte>& e, esp_netif_t *netif)
{
try {
return std::make_unique<dce>(e, netif);
} catch (std::bad_alloc& e) {
ESP_LOGE(TAG, "Out of memory");
return nullptr;
} catch (esp_err_exception& e) {
esp_err_t err = e.get_err_t();
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
ESP_LOGE(TAG, "%s", e.what());
return nullptr;
}
}
void uart_terminal::task()
{
uart_event_t event;
size_t len;
signal.set(TASK_INIT);
signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY);
if (signal.is_any(TASK_STOP)) {
return; // deletes the static task
}
while(signal.is_any(TASK_START)) {
event_loop.run();
if (uart.get_event(event, 100)) {
switch (event.type) {
case UART_DATA:
ESP_LOGI(TAG, "UART_DATA");
uart_get_buffered_data_len(uart.port, &len);
ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data);
if (len && on_data) {
on_data(len);
}
break;
case UART_FIFO_OVF:
ESP_LOGW(TAG, "HW FIFO Overflow");
uart.reset_events();
break;
case UART_BUFFER_FULL:
ESP_LOGW(TAG, "Ring Buffer Full");
uart.reset_events();
break;
case UART_BREAK:
ESP_LOGW(TAG, "Rx Break");
break;
case UART_PARITY_ERR:
ESP_LOGE(TAG, "Parity Error");
break;
case UART_FRAME_ERR:
ESP_LOGE(TAG, "Frame Error");
break;
case UART_PATTERN_DET:
ESP_LOGI(TAG, "UART_PATTERN_DET");
break;
default:
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
break;
}
}
// ESP_LOGI(TAG, "uart_event_task_entry");
// vTaskDelay(pdMS_TO_TICKS(200));
}
}
int uart_terminal::read(uint8_t *data, size_t len)
{
size_t length = 0;
uart_get_buffered_data_len(uart.port, &length);
if (length > 0) {
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);
}
return 0;
}
int uart_terminal::write(uint8_t *data, size_t len)
{
return uart_write_bytes(uart.port, data, len);
}
dte::dte(std::unique_ptr<terminal> terminal):
buffer_size(DTE_BUFFER_SIZE), consumed(0),
buffer(std::make_unique<uint8_t[]>(buffer_size)),
term(std::move(terminal)), mode(dte_mode::UNDEF) {}
bool dte::send_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)
{
command_result res = command_result::TIMEOUT;
term->write((uint8_t *)command.c_str(), command.length());
term->set_data_cb([&](size_t len){
auto data_to_read = std::min(len, buffer_size - consumed);
@ -336,18 +18,17 @@ bool dte::send_command(const std::string& command, got_line_cb got_line, uint32_
auto actual_len = term->read(data, data_to_read);
consumed += actual_len;
if (memchr(data, '\n', actual_len)) {
ESP_LOGD("in the lambda", "FOUND");
if (got_line(buffer.get(), consumed)) {
res = got_line(buffer.get(), consumed);
if (res == command_result::OK || res == command_result::FAIL) {
signal.set(GOT_LINE);
}
}
});
auto res = signal.wait(GOT_LINE, time_ms);
auto got_lf = signal.wait(GOT_LINE, time_ms);
if (got_lf && res == command_result::TIMEOUT) {
throw_if_esp_fail(ESP_ERR_INVALID_STATE);
}
consumed = 0;
term->set_data_cb(nullptr);
return res;
}
dce::dce(std::shared_ptr<dte> e, esp_netif_t * netif):
dce_dte(e), ppp_netif(e, netif)
{ }
}

View File

@ -0,0 +1,246 @@
#include "cxx_include/esp_modem_dte.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_event.h"
#include "driver/uart.h"
#include "esp_modem_dte_config.h"
#define ESP_MODEM_EVENT_QUEUE_SIZE (16)
static const char *TAG = "uart_terminal";
struct uart_resource {
explicit uart_resource(const struct dte_config *config);
~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 */
int line_buffer_size; /*!< line buffer size in command mode */
int pattern_queue_size; /*!< UART pattern queue size */
};
struct uart_task {
explicit uart_task(size_t stack_size, size_t priority, void* task_param, TaskFunction_t task_function):
task_handle(nullptr)
{
BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle);
throw_if_false(ret == pdTRUE, "create uart event task failed");
}
~uart_task()
{
if (task_handle) vTaskDelete(task_handle);
}
TaskHandle_t task_handle; /*!< UART event task handle */
};
struct uart_event_loop {
explicit uart_event_loop(): event_loop_hdl(nullptr)
{
esp_event_loop_args_t loop_args = {};
loop_args.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE;
loop_args.task_name = nullptr;
throw_if_esp_fail(esp_event_loop_create(&loop_args, &event_loop_hdl), "create event loop failed");
}
void run() { esp_event_loop_run(event_loop_hdl, pdMS_TO_TICKS(0)); }
~uart_event_loop() { if (event_loop_hdl) esp_event_loop_delete(event_loop_hdl); }
esp_event_loop_handle_t event_loop_hdl;
};
uart_resource::~uart_resource()
{
if (port >= UART_NUM_0 && port < UART_NUM_MAX) {
uart_driver_delete(port);
}
}
uart_resource::uart_resource(const struct dte_config *config):
port(-1)
{
esp_err_t res;
line_buffer_size = config->line_buffer_size;
/* Config UART */
uart_config_t uart_config = {};
uart_config.baud_rate = config->baud_rate;
uart_config.data_bits = config->data_bits;
uart_config.parity = config->parity;
uart_config.stop_bits = config->stop_bits;
uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
: UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_REF_TICK;
throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
config->rts_io_num, config->cts_io_num);
} else {
res = uart_set_pin(config->port_num, config->tx_io_num, 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->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
res = uart_set_sw_flow_ctrl(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->port_num, config->rx_buffer_size, config->tx_buffer_size,
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->port_num, 1), "set rx timeout failed");
uart_set_rx_full_threshold(config->port_num, 64);
throw_if_esp_fail(res, "config uart pattern failed");
/* mark UART as initialized */
port = config->port_num;
}
class uart_terminal: public terminal {
public:
explicit uart_terminal(const struct dte_config *config):
uart(config), event_loop(), signal(),
task_handle(config->event_task_stack_size, config->event_task_priority, this, s_task) {}
~uart_terminal() override = default;
void start() override
{
signal.set(TASK_START);
}
void stop() override
{
signal.set(TASK_STOP);
}
int write(uint8_t *data, size_t len) override;
int read(uint8_t *data, size_t len) override;
private:
static void s_task(void * task_param)
{
auto t = static_cast<uart_terminal*>(task_param);
t->task();
vTaskDelete(NULL);
}
void task();
const size_t TASK_INIT = BIT0;
const size_t TASK_START = BIT1;
const size_t TASK_STOP = BIT2;
uart_resource uart;
uart_event_loop event_loop;
signal_group signal;
uart_task task_handle;
};
std::unique_ptr<terminal> create_uart_terminal(const dte_config *config)
{
try {
auto term = std::make_unique<uart_terminal>(config);
term->start();
return term;
} catch (std::bad_alloc& e) {
ESP_LOGE(TAG, "Out of memory");
return nullptr;
} catch (esp_err_exception& e) {
esp_err_t err = e.get_err_t();
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
ESP_LOGE(TAG, "%s", e.what());
return nullptr;
}
}
void uart_terminal::task()
{
uart_event_t event;
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
}
while(signal.is_any(TASK_START)) {
event_loop.run();
if (uart.get_event(event, 100)) {
switch (event.type) {
case UART_DATA:
ESP_LOGI(TAG, "UART_DATA");
// ESP_LOG_BUFFER_HEXDUMP("esp-modem-pattern: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
uart_get_buffered_data_len(uart.port, &len);
ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data);
if (len && on_data) {
on_data(len);
}
break;
case UART_FIFO_OVF:
ESP_LOGW(TAG, "HW FIFO Overflow");
uart.reset_events();
break;
case UART_BUFFER_FULL:
ESP_LOGW(TAG, "Ring Buffer Full");
uart.reset_events();
break;
case UART_BREAK:
ESP_LOGW(TAG, "Rx Break");
break;
case UART_PARITY_ERR:
ESP_LOGE(TAG, "Parity Error");
break;
case UART_FRAME_ERR:
ESP_LOGE(TAG, "Frame Error");
break;
case UART_PATTERN_DET:
ESP_LOGI(TAG, "UART_PATTERN_DET");
break;
default:
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
break;
}
}
}
}
int uart_terminal::read(uint8_t *data, size_t len)
{
size_t length = 0;
uart_get_buffered_data_len(uart.port, &length);
if (length > 0) {
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);
}
return 0;
}
int uart_terminal::write(uint8_t *data, size_t len)
{
return uart_write_bytes(uart.port, data, len);
}

View File

@ -9,6 +9,7 @@
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_netif_ppp.h"
#include <iostream>
//struct ppp_netif_driver {
// esp_netif_driver_base_t base;
@ -17,19 +18,23 @@
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
dte *e = (dte*)arg;
ppp *e = (ppp*)arg;
// DTE *e = (DTE*)arg;
std::cout << "on_ppp_changed " << std::endl;
ESP_LOGW("TAG", "PPP state changed event %d", event_id);
if (event_id < NETIF_PP_PHASE_OFFSET) {
ESP_LOGI("TAG", "PPP state changed event %d", event_id);
// only notify the modem on state/error events, ignoring phase transitions
e->data_mode_closed();
e->notify_ppp_exit();
// e->data_mode_closed();
// esp_modem_notify_ppp_netif_closed(dte);
}
}
static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len)
{
dte *e = (dte*)h;
DTE *e = (DTE*)h;
std::cout << "sending data " << len << std::endl;
if (e->write((uint8_t*)buffer, len) > 0) {
return ESP_OK;
}
@ -42,28 +47,30 @@ static esp_err_t esp_modem_post_attach(esp_netif_t * esp_netif, void * args)
esp_netif_driver_ifconfig_t driver_ifconfig = { };
driver_ifconfig.transmit = esp_modem_dte_transmit;
driver_ifconfig.handle = (void*)d->e;
std::cout << "esp_modem_post_attach " << std::endl;
d->base.netif = esp_netif;
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig));
// check if PPP error events are enabled, if not, do enable the error occurred/state changed
// to notify the modem layer when switching modes
esp_netif_ppp_config_t 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_phase_event_enabled = true;
esp_netif_ppp_set_params(esp_netif, &ppp_config);
}
// }
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void*)d->e));
// ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, 0));
return ESP_OK;
}
void ppp::receive(uint8_t *data, size_t len) const
{
std::cout << "received data " << len << std::endl;
esp_netif_receive(driver.base.netif, data, len, nullptr);
}
ppp::ppp(std::shared_ptr<dte> e, esp_netif_t *ppp_netif):
ppp::ppp(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif):
ppp_dte(std::move(e)), netif(ppp_netif)
{
driver.base.netif = ppp_netif;
@ -74,10 +81,20 @@ ppp::ppp(std::shared_ptr<dte> e, esp_netif_t *ppp_netif):
auto actual_len = ppp_dte->read(&data, len);
return receive(data, actual_len);
});
throw_if_esp_fail(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void*)this));
throw_if_esp_fail(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_netif));
throw_if_esp_fail(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected, ppp_netif));
throw_if_esp_fail(esp_netif_attach(ppp_netif, &driver));
}
void ppp::start()
{
esp_netif_action_start(driver.base.netif, 0, 0, 0);
}
void ppp::stop()
{
std::cout << "esp_netif_action_stop " << std::endl;
esp_netif_action_stop(driver.base.netif, nullptr, 0, nullptr);
}