Added AsyncUdpListener and taskutils
This commit is contained in:
260
src/asyncudplistener.cpp
Normal file
260
src/asyncudplistener.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
#include "asyncudplistener.h"
|
||||
|
||||
// system includes
|
||||
#include <cassert>
|
||||
|
||||
// esp-idf includes
|
||||
#include <lwip/priv/tcpip_priv.h>
|
||||
#include <lwip/prot/ethernet.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
// local utils
|
||||
#include "taskutils.h"
|
||||
|
||||
namespace espcpputils {
|
||||
namespace {
|
||||
typedef struct
|
||||
{
|
||||
void *arg;
|
||||
udp_pcb *pcb;
|
||||
pbuf *pb;
|
||||
const ip_addr_t *addr;
|
||||
uint16_t port;
|
||||
struct netif *netif;
|
||||
} lwip_event_packet_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct tcpip_api_call_data call;
|
||||
udp_pcb * pcb;
|
||||
const ip_addr_t *addr;
|
||||
uint16_t port;
|
||||
struct pbuf *pb;
|
||||
struct netif *netif;
|
||||
err_t err;
|
||||
} udp_api_call_t;
|
||||
|
||||
err_t _udp_bind_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
udp_api_call_t *msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = udp_bind(msg->pcb, msg->addr, msg->port);
|
||||
return msg->err;
|
||||
}
|
||||
|
||||
err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
udp_api_call_t msg;
|
||||
msg.pcb = pcb;
|
||||
msg.addr = addr;
|
||||
msg.port = port;
|
||||
tcpip_api_call(_udp_bind_api, (struct tcpip_api_call_data*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
err_t _udp_disconnect_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
udp_api_call_t *msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = 0;
|
||||
udp_disconnect(msg->pcb);
|
||||
return msg->err;
|
||||
}
|
||||
|
||||
void _udp_disconnect(struct udp_pcb *pcb)
|
||||
{
|
||||
udp_api_call_t msg;
|
||||
msg.pcb = pcb;
|
||||
tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call_data*)&msg);
|
||||
}
|
||||
|
||||
void _udp_recv(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port)
|
||||
{
|
||||
while (pb != NULL)
|
||||
{
|
||||
pbuf *this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
|
||||
if (!AsyncUdpListener::_udp_task_post(arg, pcb, this_pb, addr, port, ip_current_input_netif()))
|
||||
pbuf_free(this_pb);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UdpPacketWrapper::UdpPacketWrapper(pbuf *pb, const ip_addr_t *raddr, uint16_t rport, struct netif *ntif)
|
||||
{
|
||||
_pb = pb;
|
||||
_if = TCPIP_ADAPTER_IF_MAX;
|
||||
_data = (uint8_t*)(pb->payload);
|
||||
_len = pb->len;
|
||||
_index = 0;
|
||||
|
||||
//memcpy(&_remoteIp, raddr, sizeof(ip_addr_t));
|
||||
_remoteIp.type = raddr->type;
|
||||
_localIp.type = _remoteIp.type;
|
||||
|
||||
eth_hdr* eth = NULL;
|
||||
const udp_hdr* udphdr = reinterpret_cast<const udp_hdr*>(_data - UDP_HLEN);
|
||||
_localPort = ntohs(udphdr->dest);
|
||||
_remotePort = ntohs(udphdr->src);
|
||||
|
||||
if (_remoteIp.type == IPADDR_TYPE_V4)
|
||||
{
|
||||
eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN);
|
||||
_localIp.u_addr.ip4.addr = iphdr->dest.addr;
|
||||
_remoteIp.u_addr.ip4.addr = iphdr->src.addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN);
|
||||
std::memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
|
||||
std::memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16);
|
||||
}
|
||||
std::memcpy(_remoteMac, eth->src.addr, 6);
|
||||
|
||||
struct netif *netif{NULL};
|
||||
void *nif{NULL};
|
||||
for (int i=0; i<TCPIP_ADAPTER_IF_MAX; i++)
|
||||
{
|
||||
tcpip_adapter_get_netif((tcpip_adapter_if_t)i, &nif);
|
||||
netif = (struct netif *)nif;
|
||||
if (netif && netif == ntif)
|
||||
{
|
||||
_if = (tcpip_adapter_if_t)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AsyncUdpListener::listen(const ip_addr_t *addr, uint16_t port)
|
||||
{
|
||||
if (!_udp_queue.constructed())
|
||||
{
|
||||
_udp_queue.construct(UBaseType_t{32}, sizeof(lwip_event_packet_t *));
|
||||
if (!_udp_queue->handle)
|
||||
{
|
||||
_udp_queue.destruct();
|
||||
ESP_LOGE("AsyncUdpListener", "xQueueCreate failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_init())
|
||||
{
|
||||
ESP_LOGE("AsyncUdpListener", "failed to init");
|
||||
return false;
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
if (addr)
|
||||
{
|
||||
IP_SET_TYPE_VAL(_pcb->local_ip, addr->type);
|
||||
IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type);
|
||||
}
|
||||
|
||||
if (_udp_bind(_pcb, addr, port) != ERR_OK)
|
||||
{
|
||||
ESP_LOGE("AsyncUdpListener", "failed to bind");
|
||||
return false;
|
||||
}
|
||||
|
||||
_connected = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AsyncUdpListener::poll(TickType_t xTicksToWait)
|
||||
{
|
||||
if (!_udp_queue.constructed())
|
||||
return;
|
||||
|
||||
lwip_event_packet_t *e{NULL};
|
||||
while (_udp_queue->receive(&e, 0) == pdTRUE)
|
||||
{
|
||||
if (!e->pb)
|
||||
{
|
||||
free((void*)(e));
|
||||
continue;
|
||||
}
|
||||
|
||||
_recv(e->pcb, e->pb, e->addr, e->port, e->netif);
|
||||
|
||||
free((void*)(e));
|
||||
}
|
||||
}
|
||||
|
||||
bool AsyncUdpListener::_udp_task_post(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif)
|
||||
{
|
||||
if (!arg)
|
||||
return false;
|
||||
|
||||
auto &queue = reinterpret_cast<AsyncUdpListener*>(arg)->_udp_queue;
|
||||
if (!queue.constructed())
|
||||
return false;
|
||||
|
||||
lwip_event_packet_t *e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
e->arg = arg;
|
||||
e->pcb = pcb;
|
||||
e->pb = pb;
|
||||
e->addr = addr;
|
||||
e->port = port;
|
||||
e->netif = netif;
|
||||
|
||||
if (queue->send(&e, portMAX_DELAY) != pdPASS)
|
||||
{
|
||||
free((void*)(e));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AsyncUdpListener::_init()
|
||||
{
|
||||
if (_pcb)
|
||||
return true;
|
||||
|
||||
_pcb = udp_new();
|
||||
if (!_pcb)
|
||||
{
|
||||
ESP_LOGE("AsyncUdpListener", "udp_new() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
udp_recv(_pcb, &_udp_recv, (void *)this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AsyncUdpListener::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif)
|
||||
{
|
||||
while (pb != NULL)
|
||||
{
|
||||
pbuf *this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
|
||||
if (_handler)
|
||||
_handler(UdpPacketWrapper{this_pb, addr, port, netif});
|
||||
|
||||
pbuf_free(this_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncUdpListener::close()
|
||||
{
|
||||
if (_pcb)
|
||||
{
|
||||
if (_connected)
|
||||
_udp_disconnect(_pcb);
|
||||
|
||||
_connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace espcpputils
|
||||
136
src/asyncudplistener.h
Normal file
136
src/asyncudplistener.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
|
||||
// esp-idf includes
|
||||
#include <lwip/ip_addr.h>
|
||||
#include <lwip/udp.h>
|
||||
#include <lwip/pbuf.h>
|
||||
#include <esp_netif.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
#include "delayedconstruction.h"
|
||||
#include "wrappers/queue.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class UdpPacketWrapper
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(UdpPacketWrapper)
|
||||
|
||||
public:
|
||||
UdpPacketWrapper(pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif);
|
||||
|
||||
const uint8_t * data() const { return _data; }
|
||||
size_t length() const { return _len; }
|
||||
bool isBroadcast() const
|
||||
{
|
||||
if (_localIp.type == IPADDR_TYPE_V6)
|
||||
return false;
|
||||
uint32_t ip = _localIp.u_addr.ip4.addr;
|
||||
return ip == 0xFFFFFFFF || ip == 0 || (ip & 0xFF000000) == 0xFF000000;
|
||||
}
|
||||
bool isMulticast() const { return ip_addr_ismulticast(&(_localIp)); }
|
||||
bool isIPv6() const { return _localIp.type == IPADDR_TYPE_V6; }
|
||||
|
||||
tcpip_adapter_if_t interface() const { return _if; }
|
||||
|
||||
std::optional<u32_t> localIP() const
|
||||
{
|
||||
if (_localIp.type != IPADDR_TYPE_V4)
|
||||
return std::nullopt;
|
||||
return _localIp.u_addr.ip4.addr;
|
||||
}
|
||||
|
||||
std::optional<std::array<u32_t, 4>> localIPv6() const
|
||||
{
|
||||
if (_localIp.type != IPADDR_TYPE_V6)
|
||||
return std::nullopt;
|
||||
return *reinterpret_cast<const std::array<u32_t, 4>*>(_localIp.u_addr.ip6.addr);
|
||||
}
|
||||
|
||||
uint16_t localPort() const { return _localPort; }
|
||||
|
||||
std::optional<u32_t> remoteIP() const
|
||||
{
|
||||
if (_remoteIp.type != IPADDR_TYPE_V4)
|
||||
return std::nullopt;
|
||||
return _remoteIp.u_addr.ip4.addr;
|
||||
}
|
||||
|
||||
std::optional<std::array<u32_t, 4>> remoteIPv6() const
|
||||
{
|
||||
if (_remoteIp.type != IPADDR_TYPE_V6)
|
||||
return std::nullopt;
|
||||
return *reinterpret_cast<const std::array<u32_t, 4>*>(_remoteIp.u_addr.ip6.addr);
|
||||
}
|
||||
|
||||
uint16_t remotePort() const { return _remotePort; }
|
||||
|
||||
void remoteMac(uint8_t * mac) const { std::memcpy(mac, _remoteMac, 6); }
|
||||
|
||||
private:
|
||||
const pbuf *_pb;
|
||||
tcpip_adapter_if_t _if;
|
||||
ip_addr_t _localIp;
|
||||
uint16_t _localPort;
|
||||
ip_addr_t _remoteIp;
|
||||
uint16_t _remotePort;
|
||||
uint8_t _remoteMac[6];
|
||||
const uint8_t *_data;
|
||||
size_t _len;
|
||||
size_t _index;
|
||||
};
|
||||
|
||||
class AsyncUdpListener
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(AsyncUdpListener)
|
||||
|
||||
public:
|
||||
AsyncUdpListener() = default;
|
||||
|
||||
void onPacket(std::function<void(const UdpPacketWrapper &packet)> cb) { _handler = cb; }
|
||||
|
||||
bool listen(const ip_addr_t *addr, uint16_t port);
|
||||
|
||||
// bool listen(const IPAddress addr, uint16_t port)
|
||||
// {
|
||||
// ip_addr_t laddr;
|
||||
// laddr.type = IPADDR_TYPE_V4;
|
||||
// laddr.u_addr.ip4.addr = addr;
|
||||
// return listen(&laddr, port);
|
||||
// }
|
||||
|
||||
// bool listen(const IPv6Address addr, uint16_t port)
|
||||
// {
|
||||
// ip_addr_t laddr;
|
||||
// laddr.type = IPADDR_TYPE_V6;
|
||||
// memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16);
|
||||
// return listen(&laddr, port);
|
||||
// }
|
||||
|
||||
bool listen(uint16_t port)
|
||||
{
|
||||
return listen(IP_ANY_TYPE, port);
|
||||
}
|
||||
|
||||
void poll(TickType_t xTicksToWait = 0);
|
||||
|
||||
static bool _udp_task_post(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif);
|
||||
|
||||
private:
|
||||
bool _init();
|
||||
void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif);
|
||||
void close();
|
||||
|
||||
private:
|
||||
cpputils::DelayedConstruction<espcpputils::queue> _udp_queue;
|
||||
udp_pcb *_pcb{};
|
||||
bool _connected{};
|
||||
std::function<void(const UdpPacketWrapper &packet)> _handler;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
44
src/esprandom.h
Normal file
44
src/esprandom.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_system.h>
|
||||
|
||||
namespace espcpputils {
|
||||
namespace {
|
||||
|
||||
class esp_random_device
|
||||
{
|
||||
public:
|
||||
using result_type = decltype(esp_random()); // should be uint32_t
|
||||
|
||||
result_type operator()() const { return esp_random(); }
|
||||
|
||||
double entropy() const { return 1.; }
|
||||
static result_type min() { return std::numeric_limits<result_type>::min(); }
|
||||
static result_type max() { return std::numeric_limits<result_type>::max(); }
|
||||
};
|
||||
|
||||
std::string randomString(std::size_t length)
|
||||
{
|
||||
static constexpr auto chars =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
auto rng = esp_random_device{};
|
||||
|
||||
auto dist = std::uniform_int_distribution{{}, std::strlen(chars) - 1};
|
||||
|
||||
auto result = std::string(length, '\0');
|
||||
std::generate_n(std::begin(result), length, [&]() { return chars[dist(rng)]; });
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace espcpputils
|
||||
52
src/lockhelper.h
Normal file
52
src/lockhelper.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class LockHelper
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(LockHelper)
|
||||
|
||||
public:
|
||||
LockHelper(QueueHandle_t _xMutex, TickType_t xTicksToWait=portMAX_DELAY) :
|
||||
xMutex{_xMutex}
|
||||
{
|
||||
locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait);
|
||||
}
|
||||
|
||||
~LockHelper()
|
||||
{
|
||||
if (locked)
|
||||
xSemaphoreGiveRecursive(xMutex);
|
||||
}
|
||||
|
||||
bool lock(TickType_t xTicksToWait=portMAX_DELAY)
|
||||
{
|
||||
if (locked)
|
||||
return false;
|
||||
|
||||
locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait);
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
bool unlock()
|
||||
{
|
||||
if (!locked)
|
||||
return false;
|
||||
|
||||
locked = !xSemaphoreGiveRecursive(xMutex);
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
private:
|
||||
const QueueHandle_t xMutex;
|
||||
bool locked;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
71
src/lockingqueue.h
Normal file
71
src/lockingqueue.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
// local includes
|
||||
#include "delayedconstruction.h"
|
||||
#include "wrappers/recursive_mutex_semaphore.h"
|
||||
#include "recursivelockhelper.h"
|
||||
|
||||
namespace espcpputils {
|
||||
template<typename T>
|
||||
class LockingQueue
|
||||
{
|
||||
public:
|
||||
void push(const T &val);
|
||||
void push(T &&val);
|
||||
|
||||
std::optional<T> tryPop();
|
||||
|
||||
void clear();
|
||||
|
||||
std::size_t size() const { return m_size; }
|
||||
|
||||
private:
|
||||
espcpputils::recursive_mutex_semaphore m_lock;
|
||||
std::queue<T> m_queue;
|
||||
std::size_t m_size{}; // double-buffered to allow for reading without taking a lock
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void LockingQueue<T>::push(const T &val)
|
||||
{
|
||||
RecursiveLockHelper helper{m_lock.handle};
|
||||
m_queue.push(val);
|
||||
m_size = m_queue.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LockingQueue<T>::push(T &&val)
|
||||
{
|
||||
RecursiveLockHelper helper{m_lock.handle};
|
||||
m_queue.emplace(std::move(val));
|
||||
m_size = m_queue.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<T> LockingQueue<T>::tryPop()
|
||||
{
|
||||
RecursiveLockHelper helper{m_lock.handle};
|
||||
if (m_queue.empty())
|
||||
return std::nullopt;
|
||||
|
||||
std::optional<T> temp = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
m_size = m_queue.size();
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LockingQueue<T>::clear()
|
||||
{
|
||||
RecursiveLockHelper helper{m_lock.handle};
|
||||
m_queue.clear();
|
||||
}
|
||||
} // namespace espcpputils
|
||||
52
src/recursivelockhelper.h
Normal file
52
src/recursivelockhelper.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class RecursiveLockHelper
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(RecursiveLockHelper)
|
||||
|
||||
public:
|
||||
RecursiveLockHelper(QueueHandle_t _xMutex, TickType_t xTicksToWait=portMAX_DELAY) :
|
||||
xMutex{_xMutex}
|
||||
{
|
||||
locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait);
|
||||
}
|
||||
|
||||
~RecursiveLockHelper()
|
||||
{
|
||||
if (locked)
|
||||
xSemaphoreGiveRecursive(xMutex);
|
||||
}
|
||||
|
||||
bool lock(TickType_t xTicksToWait=portMAX_DELAY)
|
||||
{
|
||||
if (locked)
|
||||
return false;
|
||||
|
||||
locked = xSemaphoreTakeRecursive(xMutex, xTicksToWait);
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
bool unlock()
|
||||
{
|
||||
if (!locked)
|
||||
return false;
|
||||
|
||||
locked = !xSemaphoreGiveRecursive(xMutex);
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
private:
|
||||
const QueueHandle_t xMutex;
|
||||
bool locked;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
5
src/taskutils.cpp
Normal file
5
src/taskutils.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "taskutils.h"
|
||||
|
||||
namespace espcpputils {
|
||||
IMPLEMENT_TYPESAFE_ENUM(CoreAffinity, : uint8_t, CoreAffinityValues)
|
||||
} // namespace espcpputils
|
||||
38
src/taskutils.h
Normal file
38
src/taskutils.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
// local includes
|
||||
#include "cpptypesafeenum.h"
|
||||
|
||||
namespace espcpputils {
|
||||
#define CoreAffinityValues(x) \
|
||||
x(Core0) \
|
||||
x(Core1) \
|
||||
x(Both)
|
||||
DECLARE_TYPESAFE_ENUM(CoreAffinity, : uint8_t, CoreAffinityValues)
|
||||
|
||||
namespace {
|
||||
BaseType_t createTask(TaskFunction_t pvTaskCode,
|
||||
const char * const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pvCreatedTask,
|
||||
CoreAffinity coreAffinity)
|
||||
{
|
||||
switch (coreAffinity)
|
||||
{
|
||||
case CoreAffinity::Core0:
|
||||
case CoreAffinity::Core1:
|
||||
return xTaskCreatePinnedToCore(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask, int(coreAffinity));
|
||||
case CoreAffinity::Both:
|
||||
return xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // namespace espcpputils
|
||||
33
src/wrappers/binary_semaphore.h
Normal file
33
src/wrappers/binary_semaphore.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class binary_semaphore
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(binary_semaphore)
|
||||
|
||||
public:
|
||||
binary_semaphore() :
|
||||
handle{xSemaphoreCreateBinary()}
|
||||
{}
|
||||
|
||||
~binary_semaphore() { if (handle) vSemaphoreDelete(handle); }
|
||||
|
||||
TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); }
|
||||
|
||||
UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); }
|
||||
|
||||
bool take(TickType_t xTicksToWait) { return xSemaphoreTake(handle, xTicksToWait); }
|
||||
|
||||
bool give() { return xSemaphoreGive(handle); }
|
||||
|
||||
const SemaphoreHandle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
33
src/wrappers/counting_semaphore.h
Normal file
33
src/wrappers/counting_semaphore.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class counting_semaphore
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(counting_semaphore)
|
||||
|
||||
public:
|
||||
counting_semaphore(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount) :
|
||||
handle{xSemaphoreCreateCounting(uxMaxCount, uxInitialCount)}
|
||||
{}
|
||||
|
||||
~counting_semaphore() { if (handle) vSemaphoreDelete(handle); }
|
||||
|
||||
TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); }
|
||||
|
||||
UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); }
|
||||
|
||||
bool take(TickType_t xTicksToWait) { return xSemaphoreTake(handle, xTicksToWait); }
|
||||
|
||||
bool give() { return xSemaphoreGive(handle); }
|
||||
|
||||
const SemaphoreHandle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
36
src/wrappers/event_group.h
Normal file
36
src/wrappers/event_group.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/event_groups.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class event_group
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(event_group)
|
||||
|
||||
public:
|
||||
event_group() :
|
||||
handle{xEventGroupCreate()}
|
||||
{}
|
||||
|
||||
~event_group() { if (handle) vEventGroupDelete(handle); }
|
||||
|
||||
EventBits_t waitBits(const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
|
||||
{ return xEventGroupWaitBits(handle, uxBitsToWaitFor, xClearOnExit, xWaitForAllBits, xTicksToWait); }
|
||||
|
||||
EventBits_t clearBits(const EventBits_t uxBitsToClear) { return xEventGroupClearBits(handle, uxBitsToClear); }
|
||||
|
||||
EventBits_t setBits(const EventBits_t uxBitsToSet) { return xEventGroupSetBits(handle, uxBitsToSet); }
|
||||
|
||||
EventBits_t groupSync(const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait)
|
||||
{ return xEventGroupSync(handle, uxBitsToSet, uxBitsToWaitFor, xTicksToWait); }
|
||||
|
||||
EventBits_t getBits() const { return xEventGroupClearBits(handle, 0); }
|
||||
|
||||
const EventGroupHandle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
77
src/wrappers/http_client.h
Normal file
77
src/wrappers/http_client.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <esp_http_client.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class http_client
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(http_client)
|
||||
|
||||
public:
|
||||
http_client(const esp_http_client_config_t *config) :
|
||||
handle{esp_http_client_init(config)}
|
||||
{}
|
||||
|
||||
~http_client() { if (handle) esp_http_client_cleanup(handle); }
|
||||
|
||||
esp_err_t perform() { return esp_http_client_perform(handle); }
|
||||
esp_err_t set_url(const char *url) { return esp_http_client_set_url(handle, url); }
|
||||
esp_err_t set_post_field(const char *data, int len) { return esp_http_client_set_post_field(handle, data, len); }
|
||||
int get_post_field(char **data) { return esp_http_client_get_post_field(handle, data); }
|
||||
esp_err_t set_header(const char *key, const char *value) { return esp_http_client_set_header(handle, key, value); }
|
||||
esp_err_t get_header(const char *key, char **value) { return esp_http_client_get_header(handle, key, value); }
|
||||
esp_err_t get_username(char **value) { return esp_http_client_get_username(handle, value); }
|
||||
esp_err_t set_username(const char *username) { return esp_http_client_set_username(handle, username); }
|
||||
esp_err_t get_password(char **value) { return esp_http_client_get_password(handle, value); }
|
||||
esp_err_t set_password(char *password) { return esp_http_client_set_password(handle, password); }
|
||||
esp_err_t set_method(esp_http_client_method_t method) { return esp_http_client_set_method(handle, method); }
|
||||
esp_err_t delete_header(const char *key) { return esp_http_client_delete_header(handle, key); }
|
||||
esp_err_t open(int write_len) { return esp_http_client_open(handle, write_len); }
|
||||
int write(const char *buffer, int len) { return esp_http_client_write(handle, buffer, len); }
|
||||
int fetch_headers() { return esp_http_client_fetch_headers(handle); }
|
||||
bool is_chunked_response() const { return esp_http_client_is_chunked_response(handle); }
|
||||
int read(char *buffer, int len) { return esp_http_client_read(handle, buffer, len); }
|
||||
int get_status_code() const { return esp_http_client_get_status_code(handle); }
|
||||
int get_content_length() const { return esp_http_client_get_content_length(handle); }
|
||||
esp_err_t close() { return esp_http_client_close(handle); }
|
||||
esp_http_client_transport_t get_transport_type() const { return esp_http_client_get_transport_type(handle); }
|
||||
esp_err_t set_redirection() { return esp_http_client_set_redirection(handle); }
|
||||
void add_auth() { return esp_http_client_add_auth(handle); }
|
||||
bool is_complete_data_received() const { return esp_http_client_is_complete_data_received(handle); }
|
||||
|
||||
static esp_http_client_config_t zeroInitializedConfig()
|
||||
{
|
||||
return esp_http_client_config_t {
|
||||
.url = {},
|
||||
.host = {},
|
||||
.port = {},
|
||||
.username = {},
|
||||
.password = {},
|
||||
.auth_type = {},
|
||||
.path = {},
|
||||
.query = {},
|
||||
.cert_pem = {},
|
||||
.client_cert_pem = {},
|
||||
.client_key_pem = {},
|
||||
.method = {},
|
||||
.timeout_ms = {},
|
||||
.disable_auto_redirect = {},
|
||||
.max_redirection_count = {},
|
||||
.event_handler = {},
|
||||
.transport_type = {},
|
||||
.buffer_size = {},
|
||||
.buffer_size_tx = {},
|
||||
.user_data = {},
|
||||
.is_async = {},
|
||||
.use_global_ca_store = {},
|
||||
.skip_cert_common_name_check = {}
|
||||
};
|
||||
}
|
||||
|
||||
const esp_http_client_handle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
33
src/wrappers/mutex_semaphore.h
Normal file
33
src/wrappers/mutex_semaphore.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class mutex_semaphore
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(mutex_semaphore)
|
||||
|
||||
public:
|
||||
mutex_semaphore() :
|
||||
handle{xSemaphoreCreateMutex()}
|
||||
{}
|
||||
|
||||
~mutex_semaphore() { if (handle) vSemaphoreDelete(handle); }
|
||||
|
||||
TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); }
|
||||
|
||||
UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); }
|
||||
|
||||
bool take(TickType_t xTicksToWait) { return xSemaphoreTake(handle, xTicksToWait); }
|
||||
|
||||
bool give() { return xSemaphoreGive(handle); }
|
||||
|
||||
const SemaphoreHandle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
50
src/wrappers/queue.h
Normal file
50
src/wrappers/queue.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class queue
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(queue)
|
||||
|
||||
public:
|
||||
queue(const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize) :
|
||||
handle{xQueueCreate(uxQueueLength, uxItemSize)}
|
||||
{}
|
||||
|
||||
~queue() { if (handle) vQueueDelete(handle); }
|
||||
|
||||
BaseType_t send(const void * pvItemToQueue, TickType_t xTicksToWait) { return xQueueSend(handle, pvItemToQueue, xTicksToWait); }
|
||||
|
||||
BaseType_t sendToBack(const void * pvItemToQueue, TickType_t xTicksToWait) { return xQueueSendToBack(handle, pvItemToQueue, xTicksToWait); }
|
||||
|
||||
BaseType_t sendToFront(const void * pvItemToQueue, TickType_t xTicksToWait) { return xQueueSendToFront(handle, pvItemToQueue, xTicksToWait); }
|
||||
|
||||
BaseType_t receive(void *pvBuffer, TickType_t xTicksToWait) { return xQueueReceive(handle, pvBuffer, xTicksToWait); }
|
||||
|
||||
UBaseType_t messagesWaiting() const { return uxQueueMessagesWaiting(handle); }
|
||||
|
||||
UBaseType_t spacesAvailable() const { return uxQueueSpacesAvailable(handle); }
|
||||
|
||||
BaseType_t reset() { return xQueueReset(handle); }
|
||||
|
||||
BaseType_t overwrite(const void * pvItemToQueue) { return xQueueOverwrite(handle, pvItemToQueue); }
|
||||
|
||||
BaseType_t peek(void *pvBuffer, TickType_t xTicksToWait) const { return xQueuePeek(handle, pvBuffer, xTicksToWait); }
|
||||
|
||||
#if( configQUEUE_REGISTRY_SIZE > 0 )
|
||||
void addToRegistry(char *pcQueueName) { return vQueueAddToRegistry(handle, pcQueueName); }
|
||||
|
||||
void unregisterQueue() { return vQueueUnregisterQueue(handle); }
|
||||
|
||||
const char *getName() const { return pcQueueGetName(handle); }
|
||||
#endif
|
||||
|
||||
const QueueHandle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
33
src/wrappers/recursive_mutex_semaphore.h
Normal file
33
src/wrappers/recursive_mutex_semaphore.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class recursive_mutex_semaphore
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(recursive_mutex_semaphore)
|
||||
|
||||
public:
|
||||
recursive_mutex_semaphore() :
|
||||
handle{xSemaphoreCreateRecursiveMutex()}
|
||||
{}
|
||||
|
||||
~recursive_mutex_semaphore() { if (handle) vSemaphoreDelete(handle); }
|
||||
|
||||
TaskHandle_t getMutexHolder() const { return xSemaphoreGetMutexHolder(handle); }
|
||||
|
||||
UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); }
|
||||
|
||||
bool takeRecursive(TickType_t xTicksToWait) { return xSemaphoreTakeRecursive(handle, xTicksToWait); }
|
||||
|
||||
bool giveRecursive() { return xSemaphoreGiveRecursive(handle); }
|
||||
|
||||
const SemaphoreHandle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
36
src/wrappers/websocket_client.h
Normal file
36
src/wrappers/websocket_client.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// espressif includes
|
||||
#include <esp_websocket_client.h>
|
||||
|
||||
// local includes
|
||||
#include "cppmacros.h"
|
||||
|
||||
namespace espcpputils {
|
||||
class websocket_client
|
||||
{
|
||||
CPP_DISABLE_COPY_MOVE(websocket_client)
|
||||
|
||||
public:
|
||||
websocket_client(const esp_websocket_client_config_t &config) :
|
||||
handle{esp_websocket_client_init(&config)}
|
||||
{
|
||||
}
|
||||
|
||||
~websocket_client() { if (handle) esp_websocket_client_destroy(handle); }
|
||||
|
||||
esp_err_t set_uri (const char *uri) { return esp_websocket_client_set_uri (handle, uri); }
|
||||
esp_err_t start () { return esp_websocket_client_start (handle); }
|
||||
esp_err_t stop () { return esp_websocket_client_stop (handle); }
|
||||
int send (const char *data, int len, TickType_t timeout) { return esp_websocket_client_send (handle, data, len, timeout); }
|
||||
int send_bin (const char *data, int len, TickType_t timeout) { return esp_websocket_client_send_bin (handle, data, len, timeout); }
|
||||
int send_text (const char *data, int len, TickType_t timeout) { return esp_websocket_client_send_text (handle, data, len, timeout); }
|
||||
//esp_err_t close (TickType_t timeout) { return esp_websocket_client_close (handle, timeout); }
|
||||
//esp_err_t close_with_code(int code, const char *data, int len, TickType_t timeout) { return esp_websocket_client_close_with_code(handle, code, data, len, timeout); }
|
||||
bool is_connected () const { return esp_websocket_client_is_connected (handle); }
|
||||
esp_err_t register_events(esp_websocket_event_id_t event, esp_event_handler_t event_handler, void *event_handler_arg)
|
||||
{ return esp_websocket_register_events(handle, event, event_handler, event_handler_arg); }
|
||||
|
||||
const esp_websocket_client_handle_t handle;
|
||||
};
|
||||
} // namespace espcpputils
|
||||
Reference in New Issue
Block a user