From 921e02805cc08b15ba2f837a0f317bd62839e858 Mon Sep 17 00:00:00 2001
From: "Earle F. Philhower, III" <earlephilhower@yahoo.com>
Date: Fri, 26 Apr 2024 14:26:04 -0700
Subject: [PATCH 1/3] Add support for Arduino-Pico RP2040

Only minor differences between the ESP8266 and RP2040 cores.

One new[]/delete[] error detected by GCC and fixed here.
---
 library.properties        |  6 +++---
 src/AsyncPrinter.cpp      | 24 ++++++++++++++++++++++++
 src/ESPAsyncTCP.cpp       |  2 ++
 src/ESPAsyncTCPbuffer.cpp | 26 ++++++++++++++++++++++----
 src/SyncClient.cpp        |  2 ++
 5 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/library.properties b/library.properties
index 42b23fa..1a6a9b8 100644
--- a/library.properties
+++ b/library.properties
@@ -1,9 +1,9 @@
 name=ESP AsyncTCP
-version=1.2.2
+version=1.2.3
 author=Me-No-Dev
 maintainer=Me-No-Dev
-sentence=Async TCP Library for ESP8266 and ESP31B
-paragraph=Async TCP Library for ESP8266 and ESP31B
+sentence=Async TCP Library for ESP8266 and ESP31B and RP2040 Pico
+paragraph=Async TCP Library for ESP8266 and ESP31B and RP2040 Pico
 category=Other
 url=https://github.com/me-no-dev/ESPAsyncTCP
 architectures=*
diff --git a/src/AsyncPrinter.cpp b/src/AsyncPrinter.cpp
index 8a63f20..5a1acea 100644
--- a/src/AsyncPrinter.cpp
+++ b/src/AsyncPrinter.cpp
@@ -45,7 +45,11 @@ AsyncPrinter::AsyncPrinter(AsyncClient *client, size_t txBufLen)
   _attachCallbacks();
   _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size);
   if(_tx_buffer == NULL) {
+#if defined(ARDUINO_ARCH_RP2040)
+    panic("OOM"); //What should we do?
+#else
     panic(); //What should we do?
+#endif
   }
 }
 
@@ -68,7 +72,11 @@ int AsyncPrinter::connect(IPAddress ip, uint16_t port){
     return 0;
   _client = new (std::nothrow) AsyncClient();
   if (_client == NULL) {
+#if defined(ARDUINO_ARCH_RP2040)
+    panic("OOM");
+#else
     panic();
+#endif
   }
 
   _client->onConnect([](void *obj, AsyncClient *c){ ((AsyncPrinter*)(obj))->_onConnect(c); }, this);
@@ -85,7 +93,11 @@ int AsyncPrinter::connect(const char *host, uint16_t port){
     return 0;
   _client = new (std::nothrow) AsyncClient();
   if (_client == NULL) {
+#if defined(ARDUINO_ARCH_RP2040)
+    panic("OOM");
+#else
     panic();
+#endif
   }
 
   _client->onConnect([](void *obj, AsyncClient *c){ ((AsyncPrinter*)(obj))->_onConnect(c); }, this);
@@ -106,7 +118,11 @@ void AsyncPrinter::_onConnect(AsyncClient *c){
   }
   _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size);
   if(_tx_buffer) {
+#if defined(ARDUINO_ARCH_RP2040)
+    panic("OOM");
+#else
     panic();
+#endif
   }
 
   _attachCallbacks();
@@ -127,7 +143,11 @@ AsyncPrinter & AsyncPrinter::operator=(const AsyncPrinter &other){
   }
   _tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size);
   if(_tx_buffer == NULL) {
+#if defined(ARDUINO_ARCH_RP2040)
+    panic("OOM");
+#else
     panic();
+#endif
   }
 
   _client = other._client;
@@ -179,7 +199,11 @@ size_t AsyncPrinter::_sendBuffer(){
     available= sendable;
   char *out = new (std::nothrow) char[available];
   if (out == NULL) {
+#if defined(ARDUINO_ARCH_RP2040)
+    panic("OOM"); // Connection should be aborted instead
+#else
     panic(); // Connection should be aborted instead
+#endif
   }
 
   _tx_buffer->read(out, available);
diff --git a/src/ESPAsyncTCP.cpp b/src/ESPAsyncTCP.cpp
index 7a9fdc7..510af15 100644
--- a/src/ESPAsyncTCP.cpp
+++ b/src/ESPAsyncTCP.cpp
@@ -703,6 +703,8 @@ void AsyncClient::_dns_found(const ip_addr *ipaddr){
   if(ipaddr){
 #if ASYNC_TCP_SSL_ENABLED
     connect(IPAddress(ipaddr->addr), _connect_port, _pcb_secure);
+#elif defined(ARDUINO_ARCH_RP2040)
+    connect(IPAddress((const ip_addr_t*)ipaddr), _connect_port);
 #else
     connect(IPAddress(ipaddr->addr), _connect_port);
 #endif
diff --git a/src/ESPAsyncTCPbuffer.cpp b/src/ESPAsyncTCPbuffer.cpp
index d2261da..3ec130c 100644
--- a/src/ESPAsyncTCPbuffer.cpp
+++ b/src/ESPAsyncTCPbuffer.cpp
@@ -24,7 +24,9 @@
 
 
 #include <Arduino.h>
+#if !defined(ARDUINO_ARCH_RP2040)
 #include <debug.h>
+#endif
 
 #include "ESPAsyncTCPbuffer.h"
 
@@ -32,7 +34,11 @@
 AsyncTCPbuffer::AsyncTCPbuffer(AsyncClient* client) {
     if(client == NULL) {
         DEBUG_ASYNC_TCP("[A-TCP] client is null!!!\n");
+#if defined(ARDUINO_ARCH_RP2040)
+        panic("[A-TCP] client is null!!!\n");
+#else
         panic();
+#endif
     }
 
     _client = client;
@@ -116,7 +122,11 @@ size_t AsyncTCPbuffer::write(const uint8_t *data, size_t len) {
         if(_TXbufferWrite->full() && bytesLeft > 0) {
 
             // to less ram!!!
+#if defined(ARDUINO_ARCH_RP2040)
+            if(rp2040.getFreeHeap() < 4096) {
+#else
             if(ESP.getFreeHeap() < 4096) {
+#endif
                 DEBUG_ASYNC_TCP("[A-TCP] run out of Heap can not send all Data!\n");
                 return (len - bytesLeft);
             }
@@ -124,7 +134,11 @@ size_t AsyncTCPbuffer::write(const uint8_t *data, size_t len) {
             cbuf * next = new (std::nothrow) cbuf(TCP_MSS);
             if(next == NULL) {
                 DEBUG_ASYNC_TCP("[A-TCP] run out of Heap!\n");
+#if defined(ARDUINO_ARCH_RP2040)
+                panic("[A-TCP] run out of Heap!\n");
+#else
                 panic();
+#endif
             } else {
                 DEBUG_ASYNC_TCP("[A-TCP] new cbuf\n");
             }
@@ -221,7 +235,7 @@ void AsyncTCPbuffer::onDisconnect(AsyncTCPbufferDisconnectCb cb) {
 
 IPAddress AsyncTCPbuffer::remoteIP() {
     if(!_client) {
-        return IPAddress(0U);
+        return IPAddress((uint32_t)0);
     }
     return _client->remoteIP();
 }
@@ -371,11 +385,11 @@ void AsyncTCPbuffer::_sendBuffer() {
         if(_TXbufferRead->available() == 0 && _TXbufferRead->next != NULL) {
             cbuf * old = _TXbufferRead;
             _TXbufferRead = _TXbufferRead->next;
-            delete old;
+            delete[] old;
             DEBUG_ASYNC_TCP("[A-TCP] delete cbuf\n");
         }
 
-        delete out;
+        delete[] out;
     }
 
 }
@@ -466,8 +480,12 @@ size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t *buf, size_t len) {
         if(BufferAvailable > 0) {
             uint8_t * b = new (std::nothrow) uint8_t[BufferAvailable];
             if(b == NULL){
+#if defined(ARDUINO_ARCH_RP2040)
+              panic("OOM"); //TODO: What action should this be ?
+#else
               panic(); //TODO: What action should this be ?
-            }
+#endif
+        }
             _RXbuffer->peek((char *) b, BufferAvailable);
             r = _cbRX(b, BufferAvailable);
             _RXbuffer->remove(r);
diff --git a/src/SyncClient.cpp b/src/SyncClient.cpp
index 8335358..c4d1a99 100644
--- a/src/SyncClient.cpp
+++ b/src/SyncClient.cpp
@@ -22,7 +22,9 @@
 #include "SyncClient.h"
 #include "ESPAsyncTCP.h"
 #include "cbuf.h"
+#if !defined(ARDUINO_ARCH_RP2040)
 #include <interrupts.h>
+#endif
 
 #define DEBUG_ESP_SYNC_CLIENT
 #if defined(DEBUG_ESP_SYNC_CLIENT) && !defined(SYNC_CLIENT_DEBUG)

From 735f10dd177975cfc59ca330ddd4fba56426fdef Mon Sep 17 00:00:00 2001
From: "Earle F. Philhower, III" <earlephilhower@yahoo.com>
Date: Fri, 26 Apr 2024 15:47:20 -0700
Subject: [PATCH 2/3] Missing cbuf emulation for RP2040

---
 src/cbuf.cpp | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/cbuf.h   |  75 +++++++++++++++++++++
 2 files changed, 259 insertions(+)
 create mode 100644 src/cbuf.cpp
 create mode 100644 src/cbuf.h

diff --git a/src/cbuf.cpp b/src/cbuf.cpp
new file mode 100644
index 0000000..44b938d
--- /dev/null
+++ b/src/cbuf.cpp
@@ -0,0 +1,184 @@
+#if defined(ARDUINO_ARCH_RP2040)
+/* 
+ cbuf.cpp - Circular buffer implementation
+ Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
+ This file is part of the esp8266 core for Arduino environment.
+ 
+ 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 <new> // std::nothrow
+#include "cbuf.h"
+//#include "c_types.h"
+#undef IRAM_ATTR
+#define IRAM_ATTR
+
+cbuf::cbuf(size_t size) :
+    next(NULL), _size(size), _buf(new char[size]), _bufend(_buf + size), _begin(_buf), _end(_begin) {
+}
+
+cbuf::~cbuf() {
+    delete[] _buf;
+}
+
+size_t cbuf::resizeAdd(size_t addSize) {
+    return resize(_size + addSize);
+}
+
+size_t cbuf::resize(size_t newSize) {
+
+    size_t bytes_available = available();
+
+	// not lose any data
+	// if data can be lost use remove or flush before resize
+    if((newSize <= bytes_available) || (newSize == _size)) {
+        return _size;
+    }
+
+    char *newbuf = new (std::nothrow) char[newSize];
+    char *oldbuf = _buf;
+
+    if(!newbuf) {
+        return _size;
+    }
+
+    if(_buf) {
+        read(newbuf, bytes_available);
+        memset((newbuf + bytes_available), 0x00, (newSize - bytes_available));
+    }
+
+    _begin = newbuf;
+    _end = newbuf + bytes_available;
+    _bufend = newbuf + newSize;
+    _size = newSize;
+
+    _buf = newbuf;
+    delete[] oldbuf;
+
+    return _size;
+}
+
+size_t IRAM_ATTR cbuf::available() const {
+    if(_end >= _begin) {
+        return _end - _begin;
+    }
+    return _size - (_begin - _end);
+}
+
+size_t cbuf::size() {
+    return _size;
+}
+
+size_t cbuf::room() const {
+    if(_end >= _begin) {
+        return _size - (_end - _begin) - 1;
+    }
+    return _begin - _end - 1;
+}
+
+int cbuf::peek() {
+    if(empty())
+        return -1;
+
+    return static_cast<int>(*_begin);
+}
+
+size_t cbuf::peek(char *dst, size_t size) {
+    size_t bytes_available = available();
+    size_t size_to_read = (size < bytes_available) ? size : bytes_available;
+    size_t size_read = size_to_read;
+    char * begin = _begin;
+    if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) {
+        size_t top_size = _bufend - _begin;
+        memcpy(dst, _begin, top_size);
+        begin = _buf;
+        size_to_read -= top_size;
+        dst += top_size;
+    }
+    memcpy(dst, begin, size_to_read);
+    return size_read;
+}
+
+int IRAM_ATTR cbuf::read() {
+    if(empty())
+        return -1;
+
+    char result = *_begin;
+    _begin = wrap_if_bufend(_begin + 1);
+    return static_cast<int>(result);
+}
+
+size_t cbuf::read(char* dst, size_t size) {
+    size_t bytes_available = available();
+    size_t size_to_read = (size < bytes_available) ? size : bytes_available;
+    size_t size_read = size_to_read;
+    if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) {
+        size_t top_size = _bufend - _begin;
+        memcpy(dst, _begin, top_size);
+        _begin = _buf;
+        size_to_read -= top_size;
+        dst += top_size;
+    }
+    memcpy(dst, _begin, size_to_read);
+    _begin = wrap_if_bufend(_begin + size_to_read);
+    return size_read;
+}
+
+size_t IRAM_ATTR cbuf::write(char c) {
+    if(full())
+        return 0;
+
+    *_end = c;
+    _end = wrap_if_bufend(_end + 1);
+    return 1;
+}
+
+size_t cbuf::write(const char* src, size_t size) {
+    size_t bytes_available = room();
+    size_t size_to_write = (size < bytes_available) ? size : bytes_available;
+    size_t size_written = size_to_write;
+    if(_end >= _begin && size_to_write > (size_t) (_bufend - _end)) {
+        size_t top_size = _bufend - _end;
+        memcpy(_end, src, top_size);
+        _end = _buf;
+        size_to_write -= top_size;
+        src += top_size;
+    }
+    memcpy(_end, src, size_to_write);
+    _end = wrap_if_bufend(_end + size_to_write);
+    return size_written;
+}
+
+void cbuf::flush() {
+    _begin = _buf;
+    _end = _buf;
+}
+
+size_t cbuf::remove(size_t size) {
+    size_t bytes_available = available();
+    if(size >= bytes_available) {
+        flush();
+        return 0;
+    }
+    size_t size_to_remove = (size < bytes_available) ? size : bytes_available;
+    if(_end < _begin && size_to_remove > (size_t) (_bufend - _begin)) {
+        size_t top_size = _bufend - _begin;
+        _begin = _buf;
+        size_to_remove -= top_size;
+    }
+    _begin = wrap_if_bufend(_begin + size_to_remove);
+    return available();
+}
+#endif
diff --git a/src/cbuf.h b/src/cbuf.h
new file mode 100644
index 0000000..9c358a7
--- /dev/null
+++ b/src/cbuf.h
@@ -0,0 +1,75 @@
+/* 
+ cbuf.h - Circular buffer implementation
+ Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
+ This file is part of the esp8266 core for Arduino environment.
+ 
+ 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 __cbuf_h
+#define __cbuf_h
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+class cbuf {
+    public:
+        cbuf(size_t size);
+        ~cbuf();
+
+        size_t resizeAdd(size_t addSize);
+        size_t resize(size_t newSize);
+        size_t available() const;
+        size_t size();
+
+        size_t room() const;
+
+        inline bool empty() const {
+            return _begin == _end;
+        }
+
+        inline bool full() const {
+            return wrap_if_bufend(_end + 1) == _begin;
+        }
+
+        int peek();
+        size_t peek(char *dst, size_t size);
+
+        int read();
+        size_t read(char* dst, size_t size);
+
+        size_t write(char c);
+        size_t write(const char* src, size_t size);
+
+        void flush();
+        size_t remove(size_t size);
+
+        cbuf *next;
+
+    private:
+        inline char* wrap_if_bufend(char* ptr) const {
+            return (ptr == _bufend) ? _buf : ptr;
+        }
+
+        size_t _size;
+        char* _buf;
+        const char* _bufend;
+        char* _begin;
+        char* _end;
+
+};
+
+#endif//__cbuf_h

From 8f411e1400bfa16690351f32681d51f488c7d9af Mon Sep 17 00:00:00 2001
From: "Earle F. Philhower, III" <earlephilhower@yahoo.com>
Date: Fri, 26 Apr 2024 15:50:54 -0700
Subject: [PATCH 3/3] One more mismatched delete[] (vs delete)

---
 src/AsyncPrinter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/AsyncPrinter.cpp b/src/AsyncPrinter.cpp
index 5a1acea..d23e4e7 100644
--- a/src/AsyncPrinter.cpp
+++ b/src/AsyncPrinter.cpp
@@ -208,7 +208,7 @@ size_t AsyncPrinter::_sendBuffer(){
 
   _tx_buffer->read(out, available);
   size_t sent = _client->write(out, available);
-  delete out;
+  delete[] out;
   return sent;
 }