mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-21 14:32:21 +02:00
fix(common): Improve linux port
This commit is contained in:
@ -9,6 +9,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "bsd/string.h"
|
#include "bsd/string.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct esp_timer *esp_timer_handle_t;
|
typedef struct esp_timer *esp_timer_handle_t;
|
||||||
|
|
||||||
typedef void (*esp_timer_cb_t)(void *arg);
|
typedef void (*esp_timer_cb_t)(void *arg);
|
||||||
@ -34,3 +39,7 @@ esp_err_t esp_timer_stop(esp_timer_handle_t timer);
|
|||||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
||||||
|
|
||||||
int64_t esp_timer_get_time(void);
|
int64_t esp_timer_get_time(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -117,7 +117,7 @@ void vQueueDelete( QueueHandle_t xQueue )
|
|||||||
{
|
{
|
||||||
struct generic_queue_handle *h = xQueue;
|
struct generic_queue_handle *h = xQueue;
|
||||||
if (h->q) {
|
if (h->q) {
|
||||||
if (h->type == MUTEX) {
|
if (h->type == MUTEX || h->type == MUTEX_REC) {
|
||||||
osal_mutex_delete(h->q);
|
osal_mutex_delete(h->q);
|
||||||
} else {
|
} else {
|
||||||
osal_queue_delete(h->q);
|
osal_queue_delete(h->q);
|
||||||
|
@ -32,6 +32,5 @@ typedef int BaseType_t;
|
|||||||
|
|
||||||
#define pdMS_TO_TICKS(tick) (tick)
|
#define pdMS_TO_TICKS(tick) (tick)
|
||||||
|
|
||||||
uint32_t esp_get_free_heap_size(void);
|
|
||||||
uint32_t esp_random(void);
|
uint32_t esp_random(void);
|
||||||
void vTaskSuspendAll(void);
|
void vTaskSuspendAll(void);
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include "osal_api.h"
|
#include "osal_api.h"
|
||||||
|
|
||||||
|
|
||||||
|
class SignalGroup {
|
||||||
|
|
||||||
struct SignalGroupInternal {
|
struct SignalGroupInternal {
|
||||||
std::condition_variable notify;
|
std::condition_variable notify;
|
||||||
std::mutex m;
|
std::mutex m;
|
||||||
@ -15,11 +18,8 @@ struct SignalGroupInternal {
|
|||||||
|
|
||||||
using SignalT = std::unique_ptr<SignalGroupInternal>;
|
using SignalT = std::unique_ptr<SignalGroupInternal>;
|
||||||
|
|
||||||
class SignalGroup {
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit SignalGroup(): event_group(std::make_unique<SignalGroupInternal>()) {}
|
|
||||||
|
|
||||||
void set(uint32_t bits)
|
void set(uint32_t bits)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(event_group->m);
|
std::unique_lock<std::mutex> lock(event_group->m);
|
||||||
@ -61,10 +61,8 @@ public:
|
|||||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] { return flags & event_group->flags; });
|
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] { return flags & event_group->flags; });
|
||||||
}
|
}
|
||||||
|
|
||||||
~SignalGroup() = default;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SignalT event_group;
|
SignalT event_group{std::make_unique<SignalGroupInternal>()};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,9 +16,6 @@
|
|||||||
template <class T>
|
template <class T>
|
||||||
class Queue {
|
class Queue {
|
||||||
public:
|
public:
|
||||||
Queue(): q(), m(), c() {}
|
|
||||||
~Queue() {}
|
|
||||||
|
|
||||||
void send(std::unique_ptr<T> t)
|
void send(std::unique_ptr<T> t)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m);
|
std::lock_guard<std::mutex> lock(m);
|
||||||
@ -26,11 +23,11 @@ public:
|
|||||||
c.notify_one();
|
c.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<T> receive(uint32_t ms)
|
std::unique_ptr<T> receive(std::chrono::milliseconds ms)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m);
|
std::unique_lock<std::mutex> lock(m);
|
||||||
while (q.empty()) {
|
while (q.empty()) {
|
||||||
if (c.wait_for(lock, std::chrono::milliseconds(ms)) == std::cv_status::timeout) {
|
if (c.wait_for(lock, ms) == std::cv_status::timeout) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,28 +37,30 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::queue<std::unique_ptr<T>> q;
|
std::queue<std::unique_ptr<T>> q{};
|
||||||
mutable std::mutex m;
|
mutable std::mutex m{};
|
||||||
std::condition_variable c;
|
std::condition_variable c{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using item_t = std::vector<uint8_t>;
|
||||||
|
|
||||||
void *osal_queue_create(void)
|
void *osal_queue_create(void)
|
||||||
{
|
{
|
||||||
auto *q = new Queue<std::vector<uint8_t>>();
|
auto *q = new Queue<item_t>();
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
void osal_queue_delete(void *q)
|
void osal_queue_delete(void *q)
|
||||||
{
|
{
|
||||||
auto *queue = static_cast<Queue<std::vector<uint8_t>> *>(q);
|
auto *queue = static_cast<Queue<item_t> *>(q);
|
||||||
delete (queue);
|
delete (queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool osal_queue_send(void *q, uint8_t *data, size_t len)
|
bool osal_queue_send(void *q, uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
auto v = std::make_unique<std::vector<uint8_t>>(len);
|
auto v = std::make_unique<item_t>(len);
|
||||||
v->assign(data, data + len);
|
v->assign(data, data + len);
|
||||||
auto queue = static_cast<Queue<std::vector<uint8_t>> *>(q);
|
auto queue = static_cast<Queue<item_t> *>(q);
|
||||||
queue->send(std::move(v));
|
queue->send(std::move(v));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -69,11 +68,11 @@ bool osal_queue_send(void *q, uint8_t *data, size_t len)
|
|||||||
|
|
||||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms)
|
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms)
|
||||||
{
|
{
|
||||||
auto queue = static_cast<Queue<std::vector<uint8_t>> *>(q);
|
auto queue = static_cast<Queue<item_t> *>(q);
|
||||||
auto v = queue->receive(ms);
|
auto v = queue->receive(std::chrono::milliseconds(ms));
|
||||||
if (v == nullptr) {
|
if (v != nullptr) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
memcpy(data, (void *)v->data(), len);
|
memcpy(data, (void *)v->data(), len);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
# This project serves as a demo to enable using esp-mqtt on ESP platform targets as well as on linux
|
||||||
# in this exact order for cmake to work correctly
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
# (Not part of the boilerplate)
|
# For ESP32 platform target
|
||||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
|
||||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||||
|
|
||||||
if(${IDF_TARGET} STREQUAL "linux")
|
if(${IDF_TARGET} STREQUAL "linux")
|
||||||
|
# For linux-target we have two options:
|
||||||
|
# - With lwIP (must be defined on command line, e.g. idf.py -DWITH_LWIP=1)
|
||||||
|
# access networking from linux `tap` interface (TAP networking mode)
|
||||||
|
# - Without lwIP (must be defined on command line, e.g. idf.py -DWITH_LWIP=0)
|
||||||
|
# no designated interface, accesses user network via linux/socket sys calls
|
||||||
if(WITH_LWIP STREQUAL 1)
|
if(WITH_LWIP STREQUAL 1)
|
||||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_tapif_io
|
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_tapif_io
|
||||||
"../../common_components/linux_compat/esp_timer")
|
"../../common_components/linux_compat/esp_timer")
|
||||||
set(COMPONENTS main esp_netif lwip protocol_examples_tapif_io startup esp_hw_support esp_system nvs_flash mqtt esp_timer)
|
set(COMPONENTS main esp_netif lwip protocol_examples_tapif_io startup esp_hw_support esp_system nvs_flash mqtt esp_timer)
|
||||||
else()
|
else()
|
||||||
list(APPEND EXTRA_COMPONENT_DIRS
|
list(APPEND EXTRA_COMPONENT_DIRS
|
||||||
"../../common_components/linux_compat/freertos"
|
|
||||||
"../../common_components/linux_compat/esp_timer"
|
"../../common_components/linux_compat/esp_timer"
|
||||||
"$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs")
|
"$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs")
|
||||||
set(COMPONENTS main nvs_flash esp-tls esp_stubs mqtt protocol_examples_common esp_timer)
|
set(COMPONENTS main nvs_flash esp-tls esp_stubs mqtt protocol_examples_common esp_timer)
|
||||||
@ -21,4 +23,4 @@ if(${IDF_TARGET} STREQUAL "linux")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(mqtt_tcp)
|
project(esp_mqtt_demo)
|
||||||
|
41
examples/mqtt/README.md
Normal file
41
examples/mqtt/README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# MQTT demo application that runs on linux
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This is a simple example demonstrating connecting to an MQTT broker, subscribing and publishing some data.
|
||||||
|
This example uses IDF build system and could be configured to be build and executed:
|
||||||
|
* for any ESP32 family chip
|
||||||
|
* for linux target
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
|
||||||
|
To run this example, you need any ESP32 development board or just PC/virtual machine/container running linux operating system.
|
||||||
|
|
||||||
|
### Host build modes
|
||||||
|
|
||||||
|
Linux build is supported in these two modes:
|
||||||
|
* `WITH_LWIP=0`: Without lwIP component. The project uses linux BSD socket interface to interact with TCP/IP stack. There's no connection phase, we use the host network as users. This mode is often referred to as user-side networking.
|
||||||
|
* `WITH_LWIP=1`: Including lwIP component, which is added to the list of required components and compiled on host. In this mode, we have to map the host network (linux TCP/IP stack) to the target network (lwip). We use IDF's [`tapif_io`](https://github.com/espressif/esp-idf/tree/master/examples/common_components/protocol_examples_tapif_io) component to create a network interface, which will be used to pass packets to and from the simulated target. Please refer to the [README](https://github.com/espressif/esp-idf/tree/master/examples/common_components/protocol_examples_tapif_io#readme) for more details about the host side networking.
|
||||||
|
|
||||||
|
### Building on linux
|
||||||
|
|
||||||
|
1) Configure linux target
|
||||||
|
```bash
|
||||||
|
idf.py --preview set-target linux
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Build the project with preferred components (with or without lwip)
|
||||||
|
```bash
|
||||||
|
idf.py -DWITH_LWIP=0 build # Building without lwip (user networking)
|
||||||
|
idf.py -DWITH_LWIP=1 build # Building with lwip (TAP networking)
|
||||||
|
```
|
||||||
|
|
||||||
|
3) Run the project
|
||||||
|
|
||||||
|
It is possible to run the project elf file directly, or using `idf.py` monitor target (no need to flash):
|
||||||
|
```bash
|
||||||
|
idf.py monitor
|
||||||
|
```
|
||||||
|
idf.py -DWITH_LWIP=0 build # Building without lwip (user networking)
|
@ -2,9 +2,3 @@ idf_component_register(SRCS "app_main.cpp"
|
|||||||
INCLUDE_DIRS ".")
|
INCLUDE_DIRS ".")
|
||||||
|
|
||||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||||
|
|
||||||
if(${IDF_TARGET} STREQUAL "linux")
|
|
||||||
if(WITH_LWIP STREQUAL "1")
|
|
||||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC WITH_LWIP)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
@ -6,8 +6,4 @@ menu "Example Configuration"
|
|||||||
help
|
help
|
||||||
URL of the broker to connect to
|
URL of the broker to connect to
|
||||||
|
|
||||||
config BROKER_URL_FROM_STDIN
|
|
||||||
bool
|
|
||||||
default y if BROKER_URL = "FROM_STDIN"
|
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -12,15 +12,13 @@
|
|||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "protocol_examples_common.h"
|
#include "protocol_examples_common.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "mqtt_client.h"
|
#include "mqtt_client.h"
|
||||||
|
|
||||||
static const char *TAG = "MQTT_EXAMPLE";
|
static const char *TAG = "esp_mqtt_demo";
|
||||||
|
|
||||||
|
|
||||||
static void log_error_if_nonzero(const char *message, int error_code)
|
static void log_error_if_nonzero(const char *message, int error_code)
|
||||||
@ -109,8 +107,6 @@ static void mqtt_app_start(void)
|
|||||||
esp_mqtt_client_start(client);
|
esp_mqtt_client_start(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "netdb.h"
|
|
||||||
|
|
||||||
extern "C" void app_main(void)
|
extern "C" void app_main(void)
|
||||||
{
|
{
|
||||||
@ -120,10 +116,10 @@ extern "C" void app_main(void)
|
|||||||
|
|
||||||
esp_log_level_set("*", ESP_LOG_INFO);
|
esp_log_level_set("*", ESP_LOG_INFO);
|
||||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||||
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
|
esp_log_level_set("esp_mqtt_demo", ESP_LOG_VERBOSE);
|
||||||
esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE);
|
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||||
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
|
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||||
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_init());
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
@ -135,13 +131,6 @@ extern "C" void app_main(void)
|
|||||||
* examples/protocols/README.md for more information about this function.
|
* examples/protocols/README.md for more information about this function.
|
||||||
*/
|
*/
|
||||||
ESP_ERROR_CHECK(example_connect());
|
ESP_ERROR_CHECK(example_connect());
|
||||||
#if CONFIG_IDF_TARGET_LINUX && WITH_LWIP
|
|
||||||
esp_netif_dns_info_t dns;
|
|
||||||
dns.ip.u_addr.ip4.addr = ipaddr_addr("8.8.8.8");
|
|
||||||
dns.ip.type = IPADDR_TYPE_V4;
|
|
||||||
ESP_ERROR_CHECK(esp_netif_set_dns_info(esp_netif_get_handle_from_ifkey("TAP"), ESP_NETIF_DNS_MAIN, &dns));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mqtt_app_start();
|
mqtt_app_start();
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user