Arduino Core 3 (#407)

* Add and remove libs and components for Arduino Core 3

* Arduino Core 3

* Add back Solo1

* Change ESP32-S3 to 4MB build

* Update README.md

* Fix retain and number of retries

* Fix rolling log

* Fix defaults

* Fix BleScanner on Solo1

* Export settings

* Import settings

* Fix HA Battery voltage

* Change submodule

* Update espMqttClient and AsyncTCP

* Webserial and MQTT/Network reconnecting

* Update nuki_ble

---------

Co-authored-by: iranl <iranl@github.com>
This commit is contained in:
iranl
2024-07-05 18:45:39 +02:00
committed by GitHub
parent 193ebb5f91
commit 6b0100fd61
236 changed files with 16390 additions and 9740 deletions

View File

@@ -29,7 +29,9 @@ extern "C"{
#include "lwip/dns.h"
#include "lwip/err.h"
}
#if CONFIG_ASYNC_TCP_USE_WDT
#include "esp_task_wdt.h"
#endif
/*
* TCP/IP Event Task
@@ -44,7 +46,7 @@ typedef struct {
void *arg;
union {
struct {
void * pcb;
tcp_pcb * pcb;
int8_t err;
} connected;
struct {
@@ -76,7 +78,7 @@ typedef struct {
};
} lwip_event_packet_t;
static xQueueHandle _async_queue;
static QueueHandle_t _async_queue;
static TaskHandle_t _async_service_task_handle = NULL;
@@ -95,7 +97,7 @@ static uint32_t _closed_index = []() {
static inline bool _init_async_event_queue(){
if(!_async_queue){
_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
_async_queue = xQueueCreate(CONFIG_ASYNC_TCP_QUEUE_SIZE, sizeof(lwip_event_packet_t *));
if(!_async_queue){
return false;
}
@@ -213,12 +215,32 @@ static void _stop_async_task(){
}
}
*/
static bool customTaskCreateUniversal(
TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
const BaseType_t xCoreID) {
#ifndef CONFIG_FREERTOS_UNICORE
if(xCoreID >= 0 && xCoreID < 2) {
return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID);
} else {
#endif
return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
#ifndef CONFIG_FREERTOS_UNICORE
}
#endif
}
static bool _start_async_task(){
if(!_init_async_event_queue()){
return false;
}
if(!_async_service_task_handle){
xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
customTaskCreateUniversal(_async_service_task, "async_tcp", CONFIG_ASYNC_TCP_STACK_SIZE, NULL, CONFIG_ASYNC_TCP_PRIORITY, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE);
if(!_async_service_task_handle){
return false;
}
@@ -555,12 +577,11 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
, _pb_cb_arg(0)
, _timeout_cb(0)
, _timeout_cb_arg(0)
, _pcb_busy(false)
, _pcb_sent_at(0)
, _ack_pcb(true)
, _rx_last_packet(0)
, _rx_since_timeout(0)
, _ack_timeout(ASYNC_MAX_ACK_TIME)
, _tx_last_packet(0)
, _rx_timeout(0)
, _rx_last_ack(0)
, _ack_timeout(CONFIG_ASYNC_TCP_MAX_ACK_TIME)
, _connect_port(0)
, prev(NULL)
, next(NULL)
@@ -568,13 +589,15 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
_pcb = pcb;
_closed_slot = -1;
if(_pcb){
_allocate_closed_slot();
_rx_last_packet = millis();
tcp_arg(_pcb, this);
tcp_recv(_pcb, &_tcp_recv);
tcp_sent(_pcb, &_tcp_sent);
tcp_err(_pcb, &_tcp_error);
tcp_poll(_pcb, &_tcp_poll, 1);
if(!_allocate_closed_slot()) {
_close();
}
}
}
@@ -674,9 +697,9 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){
* Main Public Methods
* */
bool AsyncClient::connect(IPAddress ip, uint16_t port){
bool AsyncClient::_connect(ip_addr_t addr, uint16_t port){
if (_pcb){
log_w("already connected, state %d", _pcb->state);
log_d("already connected, state %d", _pcb->state);
return false;
}
if(!_start_async_task()){
@@ -684,11 +707,12 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){
return false;
}
ip_addr_t addr;
addr.type = IPADDR_TYPE_V4;
addr.u_addr.ip4.addr = ip;
if(!_allocate_closed_slot()) {
log_e("failed to allocate: closed slot full");
return false;
}
tcp_pcb* pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
tcp_pcb* pcb = tcp_new_ip_type(addr.type);
if (!pcb){
log_e("pcb == NULL");
return false;
@@ -699,27 +723,59 @@ bool AsyncClient::connect(IPAddress ip, uint16_t port){
tcp_recv(pcb, &_tcp_recv);
tcp_sent(pcb, &_tcp_sent);
tcp_poll(pcb, &_tcp_poll, 1);
//_tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected);
_tcp_connect(pcb, _closed_slot, &addr, port,(tcp_connected_fn)&_tcp_connected);
return true;
}
bool AsyncClient::connect(const IPAddress& ip, uint16_t port){
ip_addr_t addr;
#if ESP_IDF_VERSION_MAJOR < 5
addr.u_addr.ip4.addr = ip;
addr.type = IPADDR_TYPE_V4;
#else
ip.to_ip_addr_t(&addr);
#endif
return _connect(addr, port);
}
#if LWIP_IPV6 && ESP_IDF_VERSION_MAJOR < 5
bool AsyncClient::connect(const IPv6Address& ip, uint16_t port){
ip_addr_t addr;
addr.type = IPADDR_TYPE_V6;
memcpy(addr.u_addr.ip6.addr, static_cast<const uint32_t*>(ip), sizeof(uint32_t) * 4);
return _connect(addr, port);
}
#endif
bool AsyncClient::connect(const char* host, uint16_t port){
ip_addr_t addr;
if(!_start_async_task()){
log_e("failed to start task");
return false;
}
err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this);
if(err == ERR_OK) {
#if ESP_IDF_VERSION_MAJOR < 5
#if LWIP_IPV6
if(addr.type == IPADDR_TYPE_V6) {
return connect(IPv6Address(addr.u_addr.ip6.addr), port);
}
return connect(IPAddress(addr.u_addr.ip4.addr), port);
#else
return connect(IPAddress(addr.addr), port);
#endif
#else
return _connect(addr, port);
#endif
} else if(err == ERR_INPROGRESS) {
_connect_port = port;
return true;
}
log_e("error: %d", err);
log_d("error: %d", err);
return false;
}
@@ -763,13 +819,12 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) {
}
bool AsyncClient::send(){
int8_t err = ERR_OK;
err = _tcp_output(_pcb, _closed_slot);
if(err == ERR_OK){
_pcb_busy = true;
_pcb_sent_at = millis();
auto backup = _tx_last_packet;
_tx_last_packet = millis();
if (_tcp_output(_pcb, _closed_slot) == ERR_OK) {
return true;
}
_tx_last_packet = backup;
return false;
}
@@ -799,7 +854,6 @@ int8_t AsyncClient::_close(){
//ets_printf("X: 0x%08x\n", (uint32_t)this);
int8_t err = ERR_OK;
if(_pcb) {
//log_i("");
tcp_arg(_pcb, NULL);
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
@@ -810,6 +864,7 @@ int8_t AsyncClient::_close(){
if(err != ERR_OK) {
err = abort();
}
_free_closed_slot();
_pcb = NULL;
if(_discard_cb) {
_discard_cb(_discard_cb_arg, this);
@@ -818,7 +873,10 @@ int8_t AsyncClient::_close(){
return err;
}
void AsyncClient::_allocate_closed_slot(){
bool AsyncClient::_allocate_closed_slot(){
if (_closed_slot != -1) {
return true;
}
xSemaphoreTake(_slots_lock, portMAX_DELAY);
uint32_t closed_slot_min_index = 0;
for (int i = 0; i < _number_of_closed_slots; ++ i) {
@@ -831,28 +889,27 @@ void AsyncClient::_allocate_closed_slot(){
_closed_slots[_closed_slot] = 0;
}
xSemaphoreGive(_slots_lock);
return (_closed_slot != -1);
}
void AsyncClient::_free_closed_slot(){
xSemaphoreTake(_slots_lock, portMAX_DELAY);
if (_closed_slot != -1) {
_closed_slots[_closed_slot] = _closed_index;
_closed_slot = -1;
++ _closed_index;
}
xSemaphoreGive(_slots_lock);
}
/*
* Private Callbacks
* */
int8_t AsyncClient::_connected(void* pcb, int8_t err){
int8_t AsyncClient::_connected(tcp_pcb* pcb, int8_t err){
_pcb = reinterpret_cast<tcp_pcb*>(pcb);
if(_pcb){
_rx_last_packet = millis();
_pcb_busy = false;
// tcp_recv(_pcb, &_tcp_recv);
// tcp_sent(_pcb, &_tcp_sent);
// tcp_poll(_pcb, &_tcp_poll, 1);
}
if(_connect_cb) {
_connect_cb(_connect_cb_arg, this);
@@ -869,6 +926,7 @@ void AsyncClient::_error(int8_t err) {
tcp_err(_pcb, NULL);
tcp_poll(_pcb, NULL, 0);
}
_free_closed_slot();
_pcb = NULL;
}
if(_error_cb) {
@@ -882,7 +940,7 @@ void AsyncClient::_error(int8_t err) {
//In LwIP Thread
int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) {
if(!_pcb || pcb != _pcb){
log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb);
log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb);
return ERR_OK;
}
tcp_arg(_pcb, NULL);
@@ -910,23 +968,27 @@ int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) {
}
int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) {
_rx_last_packet = millis();
//log_i("%u", len);
_pcb_busy = false;
_rx_last_ack = _rx_last_packet = millis();
if(_sent_cb) {
_sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at));
_sent_cb(_sent_cb_arg, this, len, (_rx_last_packet - _tx_last_packet));
}
return ERR_OK;
}
int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) {
while(pb != NULL) {
if(!_pcb || pcb != _pcb){
log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb);
return ERR_OK;
}
size_t total = 0;
while((pb != NULL) && (ERR_OK == err)) {
_rx_last_packet = millis();
//we should not ack before we assimilate the data
_ack_pcb = true;
pbuf *b = pb;
pb = b->next;
b->next = NULL;
total += b->len;
if(_pb_cb){
_pb_cb(_pb_cb_arg, this, b);
} else {
@@ -935,38 +997,39 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) {
}
if(!_ack_pcb) {
_rx_ack_len += b->len;
} else if(_pcb) {
_tcp_recved(_pcb, _closed_slot, b->len);
}
pbuf_free(b);
}
pbuf_free(b);
}
return ERR_OK;
return _tcp_recved(pcb, _closed_slot, total);
}
int8_t AsyncClient::_poll(tcp_pcb* pcb){
if(!_pcb){
log_w("pcb is NULL");
log_d("pcb is NULL");
return ERR_OK;
}
if(pcb != _pcb){
log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb);
log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb);
return ERR_OK;
}
uint32_t now = millis();
// ACK Timeout
if(_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){
_pcb_busy = false;
log_w("ack timeout %d", pcb->state);
if(_timeout_cb)
_timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at));
return ERR_OK;
if(_ack_timeout){
const uint32_t one_day = 86400000;
bool last_tx_is_after_last_ack = (_rx_last_ack - _tx_last_packet + one_day) < one_day;
if(last_tx_is_after_last_ack && (now - _tx_last_packet) >= _ack_timeout) {
log_d("ack timeout %d", pcb->state);
if(_timeout_cb)
_timeout_cb(_timeout_cb_arg, this, (now - _tx_last_packet));
return ERR_OK;
}
}
// RX Timeout
if(_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)){
log_w("rx timeout %d", pcb->state);
if(_rx_timeout && (now - _rx_last_packet) >= (_rx_timeout * 1000)) {
log_d("rx timeout %d", pcb->state);
_close();
return ERR_OK;
}
@@ -978,8 +1041,19 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){
}
void AsyncClient::_dns_found(struct ip_addr *ipaddr){
if(ipaddr && ipaddr->u_addr.ip4.addr){
connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port);
#if ESP_IDF_VERSION_MAJOR < 5
if(ipaddr && IP_IS_V4(ipaddr)){
connect(IPAddress(ip_addr_get_ip4_u32(ipaddr)), _connect_port);
#if LWIP_IPV6
} else if(ipaddr && ipaddr->u_addr.ip6.addr){
connect(IPv6Address(ipaddr->u_addr.ip6.addr), _connect_port);
#endif
#else
if(ipaddr) {
IPAddress ip;
ip.from_ip_addr_t(ipaddr);
connect(ip, _connect_port);
#endif
} else {
if(_error_cb) {
_error_cb(_error_cb_arg, this, -55);
@@ -1017,18 +1091,21 @@ size_t AsyncClient::write(const char* data) {
size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) {
size_t will_send = add(data, size, apiflags);
if(!will_send || !send()) {
if(!will_send) {
return 0;
}
while (connected() && !send()) {
taskYIELD();
}
return will_send;
}
void AsyncClient::setRxTimeout(uint32_t timeout){
_rx_since_timeout = timeout;
_rx_timeout = timeout;
}
uint32_t AsyncClient::getRxTimeout(){
return _rx_since_timeout;
return _rx_timeout;
}
uint32_t AsyncClient::getAckTimeout(){
@@ -1057,6 +1134,18 @@ bool AsyncClient::getNoDelay(){
return tcp_nagle_disabled(_pcb);
}
void AsyncClient::setKeepAlive(uint32_t ms, uint8_t cnt){
if(ms!=0) {
_pcb->so_options |= SOF_KEEPALIVE; //Turn on TCP Keepalive for the given pcb
// Set the time between keepalive messages in milli-seconds
_pcb->keep_idle = ms;
_pcb->keep_intvl = ms;
_pcb->keep_cnt = cnt; //The number of unanswered probes required to force closure of the socket
} else {
_pcb->so_options &= ~SOF_KEEPALIVE; //Turn off TCP Keepalive for the given pcb
}
}
uint16_t AsyncClient::getMss(){
if(!_pcb) {
return 0;
@@ -1068,9 +1157,60 @@ uint32_t AsyncClient::getRemoteAddress() {
if(!_pcb) {
return 0;
}
#if LWIP_IPV4 && LWIP_IPV6
return _pcb->remote_ip.u_addr.ip4.addr;
#else
return _pcb->remote_ip.addr;
#endif
}
#if LWIP_IPV6
ip6_addr_t AsyncClient::getRemoteAddress6() {
if(!_pcb) {
ip6_addr_t nulladdr;
ip6_addr_set_zero(&nulladdr);
return nulladdr;
}
return _pcb->remote_ip.u_addr.ip6;
}
ip6_addr_t AsyncClient::getLocalAddress6() {
if(!_pcb) {
ip6_addr_t nulladdr;
ip6_addr_set_zero(&nulladdr);
return nulladdr;
}
return _pcb->local_ip.u_addr.ip6;
}
#if ESP_IDF_VERSION_MAJOR < 5
IPv6Address AsyncClient::remoteIP6() {
return IPv6Address(getRemoteAddress6().addr);
}
IPv6Address AsyncClient::localIP6() {
return IPv6Address(getLocalAddress6().addr);
}
#else
IPAddress AsyncClient::remoteIP6() {
if (!_pcb) {
return IPAddress(IPType::IPv6);
}
IPAddress ip;
ip.from_ip_addr_t(&(_pcb->remote_ip));
return ip;
}
IPAddress AsyncClient::localIP6() {
if (!_pcb) {
return IPAddress(IPType::IPv6);
}
IPAddress ip;
ip.from_ip_addr_t(&(_pcb->local_ip));
return ip;
}
#endif
#endif
uint16_t AsyncClient::getRemotePort() {
if(!_pcb) {
return 0;
@@ -1082,7 +1222,11 @@ uint32_t AsyncClient::getLocalAddress() {
if(!_pcb) {
return 0;
}
#if LWIP_IPV4 && LWIP_IPV6
return _pcb->local_ip.u_addr.ip4.addr;
#else
return _pcb->local_ip.addr;
#endif
}
uint16_t AsyncClient::getLocalPort() {
@@ -1093,7 +1237,16 @@ uint16_t AsyncClient::getLocalPort() {
}
IPAddress AsyncClient::remoteIP() {
#if ESP_IDF_VERSION_MAJOR < 5
return IPAddress(getRemoteAddress());
#else
if (!_pcb) {
return IPAddress();
}
IPAddress ip;
ip.from_ip_addr_t(&(_pcb->remote_ip));
return ip;
#endif
}
uint16_t AsyncClient::remotePort() {
@@ -1101,9 +1254,19 @@ uint16_t AsyncClient::remotePort() {
}
IPAddress AsyncClient::localIP() {
#if ESP_IDF_VERSION_MAJOR < 5
return IPAddress(getLocalAddress());
#else
if (!_pcb) {
return IPAddress();
}
IPAddress ip;
ip.from_ip_addr_t(&(_pcb->local_ip));
return ip;
#endif
}
uint16_t AsyncClient::localPort() {
return getLocalPort();
}
@@ -1226,7 +1389,7 @@ void AsyncClient::_s_error(void * arg, int8_t err) {
reinterpret_cast<AsyncClient*>(arg)->_error(err);
}
int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){
int8_t AsyncClient::_s_connected(void * arg, struct tcp_pcb * pcb, int8_t err){
return reinterpret_cast<AsyncClient*>(arg)->_connected(pcb, err);
}
@@ -1236,6 +1399,13 @@ int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){
AsyncServer::AsyncServer(IPAddress addr, uint16_t port)
: _port(port)
#if ESP_IDF_VERSION_MAJOR < 5
, _bind4(true)
, _bind6(false)
#else
, _bind4(addr.type() != IPType::IPv6)
, _bind6(addr.type() == IPType::IPv6)
#endif
, _addr(addr)
, _noDelay(false)
, _pcb(0)
@@ -1243,9 +1413,27 @@ AsyncServer::AsyncServer(IPAddress addr, uint16_t port)
, _connect_cb_arg(0)
{}
#if ESP_IDF_VERSION_MAJOR < 5
AsyncServer::AsyncServer(IPv6Address addr, uint16_t port)
: _port(port)
, _bind4(false)
, _bind6(true)
, _addr6(addr)
, _noDelay(false)
, _pcb(0)
, _connect_cb(0)
, _connect_cb_arg(0)
{}
#endif
AsyncServer::AsyncServer(uint16_t port)
: _port(port)
, _bind4(true)
, _bind6(false)
, _addr((uint32_t) IPADDR_ANY)
#if ESP_IDF_VERSION_MAJOR < 5
, _addr6()
#endif
, _noDelay(false)
, _pcb(0)
, _connect_cb(0)
@@ -1271,15 +1459,24 @@ void AsyncServer::begin(){
return;
}
int8_t err;
_pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
_pcb = tcp_new_ip_type(_bind4 && _bind6 ? IPADDR_TYPE_ANY : (_bind6 ? IPADDR_TYPE_V6 : IPADDR_TYPE_V4));
if (!_pcb){
log_e("_pcb == NULL");
return;
}
ip_addr_t local_addr;
local_addr.type = IPADDR_TYPE_V4;
local_addr.u_addr.ip4.addr = (uint32_t) _addr;
#if ESP_IDF_VERSION_MAJOR < 5
if (_bind6) { // _bind6 && _bind4 both at the same time is not supported on Arduino 2 in this lib API
local_addr.type = IPADDR_TYPE_V6;
memcpy(local_addr.u_addr.ip6.addr, static_cast<const uint32_t*>(_addr6), sizeof(uint32_t) * 4);
} else {
local_addr.type = IPADDR_TYPE_V4;
local_addr.u_addr.ip4.addr = _addr;
}
#else
_addr.to_ip_addr_t(&local_addr);
#endif
err = _tcp_bind(_pcb, &local_addr, _port);
if (err != ERR_OK) {
@@ -1322,7 +1519,7 @@ int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){
if(tcp_close(pcb) != ERR_OK){
tcp_abort(pcb);
}
log_e("FAIL");
log_d("FAIL");
return ERR_OK;
}

View File

@@ -22,13 +22,34 @@
#ifndef ASYNCTCP_H_
#define ASYNCTCP_H_
#define ASYNCTCP_VERSION "3.1.4"
#define ASYNCTCP_VERSION_MAJOR 3
#define ASYNCTCP_VERSION_MINOR 1
#define ASYNCTCP_VERSION_REVISION 4
#define ASYNCTCP_FORK_mathieucarbou
#include "IPAddress.h"
#include "sdkconfig.h"
#if ESP_IDF_VERSION_MAJOR < 5
#include "IPv6Address.h"
#endif
#include <functional>
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#ifndef LIBRETINY
#include "sdkconfig.h"
extern "C" {
#include "freertos/semphr.h"
#include "lwip/pbuf.h"
}
#else
extern "C" {
#include <semphr.h>
#include <lwip/pbuf.h>
}
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
#define CONFIG_ASYNC_TCP_USE_WDT 0
#endif
//If core is not defined, then we are running in Arduino or PIO
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
@@ -36,9 +57,24 @@ extern "C" {
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
#endif
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
#define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2
#endif
#ifndef CONFIG_ASYNC_TCP_PRIORITY
#define CONFIG_ASYNC_TCP_PRIORITY 10
#endif
#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE
#define CONFIG_ASYNC_TCP_QUEUE_SIZE 64
#endif
#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME
#define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000
#endif
class AsyncClient;
#define ASYNC_MAX_ACK_TIME 5000
#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given)
#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react.
@@ -65,8 +101,11 @@ class AsyncClient {
bool operator!=(const AsyncClient &other) {
return !(*this == other);
}
bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port);
bool connect(const IPAddress& ip, uint16_t port);
#if ESP_IDF_VERSION_MAJOR < 5
bool connect(const IPv6Address& ip, uint16_t port);
#endif
bool connect(const char *host, uint16_t port);
void close(bool now = false);
void stop();
int8_t abort();
@@ -99,16 +138,29 @@ class AsyncClient {
void setNoDelay(bool nodelay);
bool getNoDelay();
void setKeepAlive(uint32_t ms, uint8_t cnt);
uint32_t getRemoteAddress();
uint16_t getRemotePort();
uint32_t getLocalAddress();
uint16_t getLocalPort();
#if LWIP_IPV6
ip6_addr_t getRemoteAddress6();
ip6_addr_t getLocalAddress6();
#if ESP_IDF_VERSION_MAJOR < 5
IPv6Address remoteIP6();
IPv6Address localIP6();
#else
IPAddress remoteIP6();
IPAddress localIP6();
#endif
#endif
//compatibility
IPAddress remoteIP();
uint16_t remotePort();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
@@ -133,13 +185,15 @@ class AsyncClient {
static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err);
static void _s_error(void *arg, int8_t err);
static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
static int8_t _s_connected(void* arg, struct tcp_pcb *tpcb, int8_t err);
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err);
tcp_pcb * pcb(){ return _pcb; }
protected:
bool _connect(ip_addr_t addr, uint16_t port);
tcp_pcb* _pcb;
int8_t _closed_slot;
@@ -160,19 +214,19 @@ class AsyncClient {
AcConnectHandler _poll_cb;
void* _poll_cb_arg;
bool _pcb_busy;
uint32_t _pcb_sent_at;
bool _ack_pcb;
uint32_t _tx_last_packet;
uint32_t _rx_ack_len;
uint32_t _rx_last_packet;
uint32_t _rx_since_timeout;
uint32_t _rx_timeout;
uint32_t _rx_last_ack;
uint32_t _ack_timeout;
uint16_t _connect_port;
int8_t _close();
void _free_closed_slot();
void _allocate_closed_slot();
int8_t _connected(void* pcb, int8_t err);
bool _allocate_closed_slot();
int8_t _connected(tcp_pcb* pcb, int8_t err);
void _error(int8_t err);
int8_t _poll(tcp_pcb* pcb);
int8_t _sent(tcp_pcb* pcb, uint16_t len);
@@ -188,6 +242,9 @@ class AsyncClient {
class AsyncServer {
public:
AsyncServer(IPAddress addr, uint16_t port);
#if ESP_IDF_VERSION_MAJOR < 5
AsyncServer(IPv6Address addr, uint16_t port);
#endif
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
@@ -203,7 +260,12 @@ class AsyncServer {
protected:
uint16_t _port;
bool _bind4 = false;
bool _bind6 = false;
IPAddress _addr;
#if ESP_IDF_VERSION_MAJOR < 5
IPv6Address _addr6;
#endif
bool _noDelay;
tcp_pcb* _pcb;
AcConnectHandler _connect_cb;

View File

@@ -1,90 +0,0 @@
/*
IPv6Address.cpp - Base class that provides IPv6Address
Copyright (c) 2011 Adrian McEwen. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#include <IPv6Address.h>
#include <Print.h>
IPv6Address::IPv6Address()
{
memset(_address.bytes, 0, sizeof(_address.bytes));
}
IPv6Address::IPv6Address(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
}
IPv6Address::IPv6Address(const uint32_t *address)
{
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
}
IPv6Address& IPv6Address::operator=(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
return *this;
}
bool IPv6Address::operator==(const uint8_t* addr) const
{
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
}
size_t IPv6Address::printTo(Print& p) const
{
size_t n = 0;
for(int i = 0; i < 16; i+=2) {
if(i){
n += p.print(':');
}
n += p.printf("%02x", _address.bytes[i]);
n += p.printf("%02x", _address.bytes[i+1]);
}
return n;
}
String IPv6Address::toString() const
{
char szRet[40];
sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
return String(szRet);
}
bool IPv6Address::fromString(const char *address)
{
//format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
if(strlen(address) != 39){
return false;
}
char * pos = (char *)address;
size_t i = 0;
for(i = 0; i < 16; i+=2) {
if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){
return false;
}
pos += 5;
}
return true;
}

View File

@@ -1,94 +0,0 @@
/*
IPv6Address.h - Base class that provides IPv6Address
Copyright (c) 2011 Adrian McEwen. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IPv6Address_h
#define IPv6Address_h
#include <stdint.h>
#include <WString.h>
#include <Printable.h>
// A class to make it easier to handle and pass around IP addresses
class IPv6Address: public Printable
{
private:
union {
uint8_t bytes[16]; // IPv4 address
uint32_t dword[4];
} _address;
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t* raw_address()
{
return _address.bytes;
}
public:
// Constructors
IPv6Address();
IPv6Address(const uint8_t *address);
IPv6Address(const uint32_t *address);
virtual ~IPv6Address() {}
bool fromString(const char *address);
bool fromString(const String &address) { return fromString(address.c_str()); }
operator const uint8_t*() const
{
return _address.bytes;
}
operator const uint32_t*() const
{
return _address.dword;
}
bool operator==(const IPv6Address& addr) const
{
return (_address.dword[0] == addr._address.dword[0])
&& (_address.dword[1] == addr._address.dword[1])
&& (_address.dword[2] == addr._address.dword[2])
&& (_address.dword[3] == addr._address.dword[3]);
}
bool operator==(const uint8_t* addr) const;
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const
{
return _address.bytes[index];
}
uint8_t& operator[](int index)
{
return _address.bytes[index];
}
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
IPv6Address& operator=(const uint8_t *address);
virtual size_t printTo(Print& p) const;
String toString() const;
friend class UDP;
friend class Client;
friend class Server;
};
#endif