diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d8b560f..bfd9d0a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,12 +10,14 @@ However, before reporting a bug please check through the following: If you don't find anything, please [open a new issue](https://github.com/khoih-prog/AsyncTCP_RP2040W/issues/new). +--- + ### How to submit a bug report Please ensure to specify the following: * Arduino IDE version (e.g. 1.8.19) or Platform.io version -* `RP2040` Core Version (e.g. RP2040 core v2.5.4) +* `RP2040` Core Version (e.g. RP2040 core v2.7.1) * `RP2040` Board type (e.g. RASPBERRY_PI_PICO_W) * Contextual information (e.g. what you were trying to achieve) * Simplest possible steps to reproduce @@ -24,17 +26,21 @@ Please ensure to specify the following: * Network configuration +Please be educated, civilized and constructive as you've always been. Disrespective posts against [GitHub Code of Conduct](https://docs.github.com/en/site-policy/github-terms/github-event-code-of-conduct) will be ignored and deleted. + +--- + ### Example ``` Arduino IDE version: 1.8.19 -RP2040 core v2.5.4 +RP2040 core v2.7.1 RASPBERRY_PI_PICO_W Module OS: Ubuntu 20.04 LTS -Linux xy-Inspiron-3593 5.15.0-46-generic #49~20.04.1-Ubuntu SMP Thu Aug 4 19:15:44 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux +Linux xy-Inspiron-3593 5.15.0-58-generic #64~20.04.1-Ubuntu SMP Fri Jan 6 16:42:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux Context: -I encountered a crash while using Async_AdvancedWebServer +I encountered a crash while using this library Steps to reproduce: 1. ... diff --git a/changelog.md b/changelog.md index ca46f04..de1fe71 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ ## Table of Contents * [Changelog](#changelog) + * [Releases v1.2.0](#Releases-v120) * [Releases v1.1.0](#Releases-v110) * [Initial Releases v1.0.0](#Initial-Releases-v100) @@ -23,6 +24,11 @@ ## Changelog +### Releases v1.2.0 + +1. Add complex auto-reconnect `AsyncTCPClient` and `AsyncTCP_Server` examples +2. Improve `README.md` so that links can be used in other sites, such as `PIO` + ### Releases v1.1.0 1. Fix issue with slow browsers or network diff --git a/examples/ClientServer/AsyncTCP_Client/AsyncTCP_Client.ino b/examples/ClientServer/AsyncTCP_Client/AsyncTCP_Client.ino new file mode 100644 index 0000000..3b89b62 --- /dev/null +++ b/examples/ClientServer/AsyncTCP_Client/AsyncTCP_Client.ino @@ -0,0 +1,200 @@ +/**************************************************************************************************************************** + AsyncTCPClient.ino + + For RP2040W with CYW43439 WiFi + + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi + + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) + Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W + Licensed under GPLv3 license + *****************************************************************************************************************************/ + +#include + +char ssid[] = "your_ssid"; // your network SSID (name) +char pass[] = "12345678"; // your network password (use for WPA, or use as key for WEP), length must be 8+ + +int status = WL_IDLE_STATUS; + +// Change the Server IPAddress accordingly +IPAddress serverIP(192, 168, 2, 128); + +#define TCP_PORT 5698 + +#define CHECK_INTERVAL_MS 1000L // Check connection +#define SEND_INTERVAL_MS 10000L // delay between updates, in milliseconds + +unsigned long lastCheck = SEND_INTERVAL_MS; // last time you connected to the server, in milliseconds + +AsyncClient* client = nullptr; + +bool clientConnected = false; + +bool dataReceived = false; + +#define REPLY_SIZE 64 + +static void replyToServer(void* arg) +{ + (void) arg; + + Serial.println("\n********************"); + Serial.println("New replyToServer"); + + AsyncClient* client = reinterpret_cast(arg); + + // send reply + if (client->space() > REPLY_SIZE && client->canSend()) + { + char message[REPLY_SIZE]; + sprintf(message, "This is from AsyncTCPClient @ %s", WiFi.localIP().toString().c_str()); + client->add(message, strlen(message)); + client->send(); + + dataReceived = false; + } +} + +/* event callbacks */ +static void handleData(void* arg, AsyncClient* client, void *data, size_t len) +{ + (void) arg; + + Serial.printf("\nData received from %s \n", client->remoteIP().toString().c_str()); + Serial.write((uint8_t*)data, len); + + lastCheck = millis(); + + dataReceived = true; +} + +void onConnect(void* arg, AsyncClient* client) +{ + (void) arg; + + clientConnected = true; + + Serial.printf("\nAsyncTCPClient has been connected to Server %s, port %d \n", serverIP.toString().c_str(), TCP_PORT); + + replyToServer(client); +} + +void onDisconnect(void* arg, AsyncClient* client) +{ + (void) arg; + (void) client; + + Serial.printf("\nAsyncTCPClient has been disconnected from Server %s, port %d \n", serverIP.toString().c_str(), TCP_PORT); + + clientConnected = false; +} + +void printWifiStatus() +{ + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("Local IP Address: "); + Serial.println(ip); +} + +bool connectServer() +{ + if (client) + delete(client); + + client = new AsyncClient; + + if (client) + { + client->onData(&handleData, client); + client->onConnect(&onConnect, client); + + client->onDisconnect(&onDisconnect, client); + + client->connect(serverIP, TCP_PORT); + + return true; + } + else + { + Serial.println("\nError, NULL client"); + + return false; + } +} + +void setup() +{ + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(200); + + Serial.print("\nStart AsyncTCP_Client on "); + Serial.print(BOARD_NAME); + Serial.print(" with "); + Serial.println(SHIELD_TYPE); + Serial.println(ASYNCTCP_RP2040W_VERSION); + + /////////////////////////////////// + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) + { + Serial.println("Communication with WiFi module failed!"); + + // don't continue + while (true); + } + + Serial.print(F("Connecting to SSID: ")); + Serial.println(ssid); + + status = WiFi.begin(ssid, pass); + + delay(1000); + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) + { + delay(500); + + // Connect to WPA/WPA2 network + status = WiFi.status(); + } + + printWifiStatus(); + + /////////////////////////////////// + + connectServer(); + + lastCheck = millis(); +} + +void loop() +{ + static unsigned long lastConnectCheck = CHECK_INTERVAL_MS; + + if (millis() - lastCheck > SEND_INTERVAL_MS) + { + if (clientConnected && dataReceived) + { + replyToServer(client); + } + else if ( !clientConnected || !dataReceived ) + { + Serial.printf("\nReconnecting to Server %s, port %d \n", serverIP.toString().c_str(), TCP_PORT); + + connectServer(); + } + + lastCheck = millis(); + } +} diff --git a/examples/ClientServer/AsyncTCP_Server/AsyncTCP_Server.ino b/examples/ClientServer/AsyncTCP_Server/AsyncTCP_Server.ino new file mode 100644 index 0000000..442ef4f --- /dev/null +++ b/examples/ClientServer/AsyncTCP_Server/AsyncTCP_Server.ino @@ -0,0 +1,158 @@ +/**************************************************************************************************************************** + AsyncTCPServer.ino + + For RP2040W with CYW43439 WiFi + + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi + + Based on and modified from ESPAsyncWebServer (https://github.com/me-no-dev/ESPAsyncWebServer) + Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W + Licensed under GPLv3 license + *****************************************************************************************************************************/ + +#include + +#include + +#define TCP_PORT 5698 + +static std::vector clients; // a list to hold all clients + +char ssid[] = "your_ssid"; // your network SSID (name) +char pass[] = "12345678"; // your network password (use for WPA, or use as key for WEP), length must be 8+ + +int status = WL_IDLE_STATUS; + +IPAddress serverIP; + +/* clients events */ +static void handleError(void* arg, AsyncClient* client, int8_t error) +{ + (void) arg; + + Serial.printf("\nConnection error %s from client %s \n", client->errorToString(error), client->remoteIP().toString().c_str()); +} + +#define REPLY_SIZE 64 + +static void handleData(void* arg, AsyncClient* client, void *data, size_t len) +{ + (void) arg; + + Serial.printf("\nData received from client %s \n", client->remoteIP().toString().c_str()); + Serial.write((uint8_t*)data, len); + + // reply to client + if (client->space() > REPLY_SIZE && client->canSend()) + { + char reply[REPLY_SIZE]; + sprintf(reply, "You've connected to AsyncTCPServer @ %s", serverIP.toString().c_str()); + client->add(reply, strlen(reply)); + client->send(); + } +} + +static void handleDisconnect(void* arg, AsyncClient* client) +{ + (void) arg; + + Serial.printf("\nClient %s disconnected\n", client->remoteIP().toString().c_str()); +} + +static void handleTimeOut(void* arg, AsyncClient* client, uint32_t time) +{ + (void) arg; + (void) time; + + Serial.printf("\nClient ACK timeout ip: %s\n", client->remoteIP().toString().c_str()); +} + + +/* server events */ +static void handleNewClient(void* arg, AsyncClient* client) +{ + (void) arg; + + Serial.printf("\nNew client has been connected to server, IP: %s", client->remoteIP().toString().c_str()); + + // add to list + clients.push_back(client); + + // register events + client->onData(&handleData, NULL); + client->onError(&handleError, NULL); + client->onDisconnect(&handleDisconnect, NULL); + client->onTimeout(&handleTimeOut, NULL); +} + +void printWifiStatus() +{ + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + serverIP = WiFi.localIP(); + Serial.print("Local IP Address: "); + Serial.println(serverIP); +} + +void setup() +{ + Serial.begin(115200); + + while (!Serial && millis() < 5000); + + delay(200); + + Serial.print("\nStart AsyncTCP_Server on "); + Serial.print(BOARD_NAME); + Serial.print(" with "); + Serial.println(SHIELD_TYPE); + Serial.println(ASYNCTCP_RP2040W_VERSION); + + /////////////////////////////////// + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) + { + Serial.println("Communication with WiFi module failed!"); + + // don't continue + while (true); + } + + Serial.print(F("Connecting to SSID: ")); + Serial.println(ssid); + + status = WiFi.begin(ssid, pass); + + delay(1000); + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) + { + delay(500); + + // Connect to WPA/WPA2 network + status = WiFi.status(); + } + + printWifiStatus(); + + /////////////////////////////////// + + AsyncServer* server = new AsyncServer(TCP_PORT); // start listening on tcp port 7050 + + server->onClient(&handleNewClient, server); + server->begin(); + + Serial.print(F("AsyncTCPServer is @ IP: ")); + Serial.print(serverIP); + Serial.print(F(", port: ")); + Serial.println(TCP_PORT); +} + +void loop() +{ +} diff --git a/library.json b/library.json index db752a2..31f184a 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "AsyncTCP_RP2040W", - "version": "1.1.0", + "version": "1.2.0", "keywords": "http, communication, async, websocket, webserver, async-webserver, async-tcp, async-udp, async-websocket, async-http, ssl, tls, rp2040, rp2040w, raspberry-pi-pico-w, cyw43439, wifi", "description": "Asynchronous TCP Library for RASPBERRY_PI_PICO_W using CYW43439 WiFi with arduino-pico core. This library is the base for future and more advanced Async libraries, such as AsyncWebServer_RP2040W, AsyncHTTPRequest_RP2040W, AsyncHTTPSRequest_RP2040W", "authors": diff --git a/library.properties b/library.properties index 9a61a0b..981fe8e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AsyncTCP_RP2040W -version=1.1.0 +version=1.2.0 author=Hristo Gochkov,Khoi Hoang maintainer=Khoi Hoang sentence=Asynchronous TCP Library for RASPBERRY_PI_PICO_W using CYW43439 WiFi with arduino-pico core diff --git a/src/AsyncPrinter.cpp b/src/AsyncPrinter.cpp index 30f955b..bf1e672 100644 --- a/src/AsyncPrinter.cpp +++ b/src/AsyncPrinter.cpp @@ -1,26 +1,27 @@ /**************************************************************************************************************************** AsyncPrinter.cpp - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -77,8 +78,8 @@ AsyncPrinter::AsyncPrinter(AsyncClient *client, size_t txBufLen) { _attachCallbacks(); _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - - if (_tx_buffer == NULL) + + if (_tx_buffer == NULL) { panic(); //What should we do? } @@ -86,14 +87,14 @@ AsyncPrinter::AsyncPrinter(AsyncClient *client, size_t txBufLen) ///////////////////////////////////////////////////////// -AsyncPrinter::~AsyncPrinter() +AsyncPrinter::~AsyncPrinter() { _on_close(); } ///////////////////////////////////////////////////////// -void AsyncPrinter::onData(ApDataHandler cb, void *arg) +void AsyncPrinter::onData(ApDataHandler cb, void *arg) { _data_cb = cb; _data_arg = arg; @@ -101,7 +102,7 @@ void AsyncPrinter::onData(ApDataHandler cb, void *arg) ///////////////////////////////////////////////////////// -void AsyncPrinter::onClose(ApCloseHandler cb, void *arg) +void AsyncPrinter::onClose(ApCloseHandler cb, void *arg) { _close_cb = cb; _close_arg = arg; @@ -109,80 +110,80 @@ void AsyncPrinter::onClose(ApCloseHandler cb, void *arg) ///////////////////////////////////////////////////////// -int AsyncPrinter::connect(IPAddress ip, uint16_t port) +int AsyncPrinter::connect(IPAddress ip, uint16_t port) { if (_client != NULL && connected()) return 0; - + _client = new (std::nothrow) AsyncClient(); - - if (_client == NULL) + + if (_client == NULL) { panic(); } - _client->onConnect([](void *obj, AsyncClient * c) + _client->onConnect([](void *obj, AsyncClient * c) { ((AsyncPrinter*)(obj))->_onConnect(c); }, this); - - if (_client->connect(ip, port)) + + if (_client->connect(ip, port)) { while (_client && _client->state() < 4) delay(1); - + return connected(); } - + return 0; } ///////////////////////////////////////////////////////// -int AsyncPrinter::connect(const char *host, uint16_t port) +int AsyncPrinter::connect(const char *host, uint16_t port) { if (_client != NULL && connected()) return 0; - + _client = new (std::nothrow) AsyncClient(); - - if (_client == NULL) + + if (_client == NULL) { panic(); } - _client->onConnect([](void *obj, AsyncClient * c) + _client->onConnect([](void *obj, AsyncClient * c) { ((AsyncPrinter*)(obj))->_onConnect(c); }, this); - - if (_client->connect(host, port)) + + if (_client->connect(host, port)) { while (_client && _client->state() < 4) delay(1); - + return connected(); } - + return 0; } ///////////////////////////////////////////////////////// -void AsyncPrinter::_onConnect(AsyncClient *c) +void AsyncPrinter::_onConnect(AsyncClient *c) { ASYNCTCP_RP2040W_UNUSED(c); - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; delete b; } - + _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - - if (_tx_buffer) + + if (_tx_buffer) { panic(); } @@ -192,98 +193,98 @@ void AsyncPrinter::_onConnect(AsyncClient *c) ///////////////////////////////////////////////////////// -AsyncPrinter::operator bool() +AsyncPrinter::operator bool() { return connected(); } ///////////////////////////////////////////////////////// -AsyncPrinter & AsyncPrinter::operator=(const AsyncPrinter &other) +AsyncPrinter & AsyncPrinter::operator=(const AsyncPrinter &other) { - if (_client != NULL) + if (_client != NULL) { _client->close(true); _client = NULL; } - + _tx_buffer_size = other._tx_buffer_size; - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; delete b; } - + _tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size); - - if (_tx_buffer == NULL) + + if (_tx_buffer == NULL) { panic(); } _client = other._client; _attachCallbacks(); - + return *this; } ///////////////////////////////////////////////////////// -size_t AsyncPrinter::write(uint8_t data) +size_t AsyncPrinter::write(uint8_t data) { return write(&data, 1); } ///////////////////////////////////////////////////////// -size_t AsyncPrinter::write(const uint8_t *data, size_t len) +size_t AsyncPrinter::write(const uint8_t *data, size_t len) { if (_tx_buffer == NULL || !connected()) return 0; - + size_t toWrite = 0; size_t toSend = len; - - while (_tx_buffer->room() < toSend) + + while (_tx_buffer->room() < toSend) { toWrite = _tx_buffer->room(); _tx_buffer->write((const char*)data, toWrite); - + while (connected() && !_client->canSend()) delay(0); - + if (!connected()) return 0; // or len - toSend; - + _sendBuffer(); toSend -= toWrite; } - + _tx_buffer->write((const char*)(data + (len - toSend)), toSend); - - while (connected() && !_client->canSend()) + + while (connected() && !_client->canSend()) delay(0); - - if (!connected()) + + if (!connected()) return 0; // or len - toSend; - + _sendBuffer(); - + return len; } ///////////////////////////////////////////////////////// -bool AsyncPrinter::connected() +bool AsyncPrinter::connected() { return (_client != NULL && _client->connected()); } ///////////////////////////////////////////////////////// -void AsyncPrinter::close() +void AsyncPrinter::close() { if (_client != NULL) _client->close(true); @@ -291,21 +292,21 @@ void AsyncPrinter::close() ///////////////////////////////////////////////////////// -size_t AsyncPrinter::_sendBuffer() +size_t AsyncPrinter::_sendBuffer() { size_t available = _tx_buffer->available(); - + if (!connected() || !_client->canSend() || available == 0) return 0; - + size_t sendable = _client->space(); - + if (sendable < available) available = sendable; - + char *out = new (std::nothrow) char[available]; - - if (out == NULL) + + if (out == NULL) { panic(); // Connection should be aborted instead } @@ -313,13 +314,13 @@ size_t AsyncPrinter::_sendBuffer() _tx_buffer->read(out, available); size_t sent = _client->write(out, available); delete out; - + return sent; } ///////////////////////////////////////////////////////// -void AsyncPrinter::_onData(void *data, size_t len) +void AsyncPrinter::_onData(void *data, size_t len) { if (_data_cb) _data_cb(_data_arg, this, (uint8_t*)data, len); @@ -327,20 +328,20 @@ void AsyncPrinter::_onData(void *data, size_t len) ///////////////////////////////////////////////////////// -void AsyncPrinter::_on_close() +void AsyncPrinter::_on_close() { - if (_client != NULL) + if (_client != NULL) { _client = NULL; } - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; delete b; } - + if (_close_cb) _close_cb(_close_arg, this); } @@ -366,8 +367,7 @@ void AsyncPrinter::_attachCallbacks() _client->onDisconnect([](void *obj, AsyncClient * c) { - ((AsyncPrinter*)(obj))->_on_close(); - delete c; + ((AsyncPrinter*)(obj))->_on_close(); delete c; }, this); _client->onData([](void *obj, AsyncClient * c, void *data, size_t len) diff --git a/src/AsyncPrinter.h b/src/AsyncPrinter.h index 352e6a9..6eb12cf 100644 --- a/src/AsyncPrinter.h +++ b/src/AsyncPrinter.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** AsyncPrinter.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -57,7 +58,7 @@ typedef std::function ApCloseHandler; ///////////////////////////////////////////////////////// -class AsyncPrinter: public Print +class AsyncPrinter: public Print { private: AsyncClient *_client; @@ -69,7 +70,7 @@ class AsyncPrinter: public Print size_t _tx_buffer_size; void _onConnect(AsyncClient *c); - + public: AsyncPrinter *next; diff --git a/src/AsyncTCP_RP2040W.cpp b/src/AsyncTCP_RP2040W.cpp index e30a1d8..7782318 100644 --- a/src/AsyncTCP_RP2040W.cpp +++ b/src/AsyncTCP_RP2040W.cpp @@ -1,28 +1,29 @@ /**************************************************************************************************************************** AsyncTCP_RP2040W.cpp - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ - + /************************************************************************* Asynchronous TCP library for Espressif MCUs @@ -44,56 +45,56 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *************************************************************************/ /************************************************************************* - Changes for July 2019 - - The operator "new ..." was changed to "new (std::nothrow) ...", which will - return NULL when the heap is out of memory. Without the change "soft WDT" - was the result, starting with Arduino ESP8266 Core 2.5.0. (Note, RE:"soft - WDT" - the error reporting may improve with core 2.6.) With proir core - versions the library appears to work fine. - ref: https://github.com/esp8266/Arduino/issues/6269#issue-464978944 - - To support newer lwIP versions and buffer models. All references to 1460 - were replaced with TCP_MSS. If TCP_MSS is not defined (exp. 1.4v lwIP) - 1460 is assumed. - - The AsyncTCP_RP2040W library should build for Arduino ESP8266 Core releases: - 2.3.0, 2.4.1, 2.4.2, 2.5.1, 2.5.2. It may still build with core versions - 2.4.0 and 2.5.0. I did not do any regression testing with these, since - they had too many issues and were quickly superseded. - - lwIP tcp_err() callback often resulted in crashes. The problem was a - tcp_err() would come in, while processing a send or receive in the - forground. The tcp_err() callback would be passed down to a client's - registered disconnect CB. A common problem with SyncClient and other - modules as well as some client code was: the freeing of AsyncTCP_RP2040W - AsyncClient objects via disconnect CB handlers while the library was - waiting for an operstion to finished. Attempts to access bad pointers - followed. For SyncClient this commonly occured during a call to delay(). - On return to SyncClient _client was invalid. Also the problem described by - issue #94 also surfaced - - Use of tcp_abort() required some very special handling and was very - challenging to make work without changing client API. ERR_ABRT can only be - used once on a return to lwIP for a given connection and since the - AsyncClient structure was sometimes deleted before returning to lwIP, the - state tracking became tricky. While ugly, a global variable for this - seemed to work; however, I abanded it when I saw a possible - reentrancy/concurrency issue. After several approaches I settled the - problem by creating "class ACErrorTracker" to manage the issue. - - - Additional Async Client considerations: - - The client sketch must always test if the connection is still up at loop() - entry and after the return of any function call, that may have done a - delay() or yield() or any AsyncTCP_RP2040W library family call. For example, - the connection could be lost during a call to _client->write(...). Client - sketches that delete _client as part of their onDisconnect() handler must - be very careful as _client will become invalid after calls to delay(), - yield(), etc. + Changes for July 2019 + + The operator "new ..." was changed to "new (std::nothrow) ...", which will + return NULL when the heap is out of memory. Without the change "soft WDT" + was the result, starting with Arduino ESP8266 Core 2.5.0. (Note, RE:"soft + WDT" - the error reporting may improve with core 2.6.) With proir core + versions the library appears to work fine. + ref: https://github.com/esp8266/Arduino/issues/6269#issue-464978944 + + To support newer lwIP versions and buffer models. All references to 1460 + were replaced with TCP_MSS. If TCP_MSS is not defined (exp. 1.4v lwIP) + 1460 is assumed. + + The AsyncTCP_RP2040W library should build for Arduino ESP8266 Core releases: + 2.3.0, 2.4.1, 2.4.2, 2.5.1, 2.5.2. It may still build with core versions + 2.4.0 and 2.5.0. I did not do any regression testing with these, since + they had too many issues and were quickly superseded. + + lwIP tcp_err() callback often resulted in crashes. The problem was a + tcp_err() would come in, while processing a send or receive in the + forground. The tcp_err() callback would be passed down to a client's + registered disconnect CB. A common problem with SyncClient and other + modules as well as some client code was: the freeing of AsyncTCP_RP2040W + AsyncClient objects via disconnect CB handlers while the library was + waiting for an operstion to finished. Attempts to access bad pointers + followed. For SyncClient this commonly occured during a call to delay(). + On return to SyncClient _client was invalid. Also the problem described by + issue #94 also surfaced + + Use of tcp_abort() required some very special handling and was very + challenging to make work without changing client API. ERR_ABRT can only be + used once on a return to lwIP for a given connection and since the + AsyncClient structure was sometimes deleted before returning to lwIP, the + state tracking became tricky. While ugly, a global variable for this + seemed to work; however, I abanded it when I saw a possible + reentrancy/concurrency issue. After several approaches I settled the + problem by creating "class ACErrorTracker" to manage the issue. + + + Additional Async Client considerations: + + The client sketch must always test if the connection is still up at loop() + entry and after the return of any function call, that may have done a + delay() or yield() or any AsyncTCP_RP2040W library family call. For example, + the connection could be lost during a call to _client->write(...). Client + sketches that delete _client as part of their onDisconnect() handler must + be very careful as _client will become invalid after calls to delay(), + yield(), etc. *************************************************************************/ - + #include "Arduino.h" #if !defined(_ASYNCTCP_RP2040W_LOGLEVEL_) @@ -105,12 +106,12 @@ extern "C" { -#include "lwip/ip_addr.h" -#include "lwip/opt.h" -#include "lwip/tcp.h" -#include "lwip/inet.h" -#include "lwip/dns.h" -#include "lwip/init.h" + #include "lwip/ip_addr.h" + #include "lwip/opt.h" + #include "lwip/tcp.h" + #include "lwip/inet.h" + #include "lwip/dns.h" + #include "lwip/init.h" } #include @@ -174,10 +175,8 @@ void ACErrorTracker::setErrored(size_t errorEvent) _errored = errorEvent; #ifdef DEBUG_MORE - if (_error_event_cb) _error_event_cb(_error_event_cb_arg, errorEvent); - #endif } @@ -265,7 +264,6 @@ AsyncClient::AsyncClient(tcp_pcb * pcb): tcp_poll(_pcb, &_s_poll, 1); #if ASYNC_TCP_SSL_ENABLED - if (ssl_ctx) { if (tcp_ssl_new_server(_pcb, ssl_ctx) < 0) @@ -282,7 +280,6 @@ AsyncClient::AsyncClient(tcp_pcb * pcb): _pcb_secure = true; _handshake_done = false; } - #endif } @@ -317,9 +314,9 @@ inline void clearTcpCallbacks(tcp_pcb* pcb) ///////////////////////////////////////////////// #if ASYNC_TCP_SSL_ENABLED - bool AsyncClient::connect(IPAddress ip, uint16_t port, bool secure) +bool AsyncClient::connect(IPAddress ip, uint16_t port, bool secure) #else - bool AsyncClient::connect(IPAddress ip, uint16_t port) +bool AsyncClient::connect(IPAddress ip, uint16_t port) #endif { if (_pcb) @@ -343,7 +340,6 @@ inline void clearTcpCallbacks(tcp_pcb* pcb) return false; } - #endif tcp_pcb* pcb = tcp_new(); @@ -376,9 +372,9 @@ inline void clearTcpCallbacks(tcp_pcb* pcb) ///////////////////////////////////////////////// #if ASYNC_TCP_SSL_ENABLED - bool AsyncClient::connect(const char* host, uint16_t port, bool secure) +bool AsyncClient::connect(const char* host, uint16_t port, bool secure) #else - bool AsyncClient::connect(const char* host, uint16_t port) +bool AsyncClient::connect(const char* host, uint16_t port) #endif { ip_addr_t addr; @@ -394,8 +390,7 @@ inline void clearTcpCallbacks(tcp_pcb* pcb) returnValue = connect(IPAddress(addr.addr), port); #endif - ATCP_LOGDEBUG3("connect: dns_gethostbyname => IP =", IPAddress(addr.addr), ", returnValue = ", - returnValue ? "TRUE" : "FALSE"); + ATCP_LOGDEBUG3("connect: dns_gethostbyname => IP =", IPAddress(addr.addr), ", returnValue = ", returnValue ? "TRUE" : "FALSE"); return returnValue; } @@ -435,10 +430,10 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other) if (_pcb) { _rx_last_packet = millis(); - + //tcp_setprio(_pcb, TCP_PRIO_MIN); tcp_setprio(_pcb, TCP_PRIO_NORMAL); - + tcp_arg(_pcb, this); tcp_recv(_pcb, &_s_recv); tcp_sent(_pcb, &_s_sent); @@ -446,7 +441,6 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other) tcp_poll(_pcb, &_s_poll, 1); #if ASYNC_TCP_SSL_ENABLED - if (tcp_ssl_has(_pcb)) { _pcb_secure = true; @@ -461,7 +455,6 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other) _pcb_secure = false; _handshake_done = true; } - #endif } @@ -473,7 +466,7 @@ AsyncClient& AsyncClient::operator=(const AsyncClient& other) bool AsyncClient::operator==(const AsyncClient &other) { return (_pcb != NULL && other._pcb != NULL && (_pcb->remote_ip.addr == other._pcb->remote_ip.addr) && - (_pcb->remote_port == other._pcb->remote_port)); + (_pcb->remote_port == other._pcb->remote_port)); } ///////////////////////////////////////////////// @@ -571,7 +564,6 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) return 0; #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure) { int sent = tcp_ssl_write(_pcb, (uint8_t*)data, size); @@ -583,10 +575,9 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) } _close(); - + return 0; } - #endif size_t will_send = (room < size) ? room : size; @@ -607,10 +598,8 @@ size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) bool AsyncClient::send() { #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure) return true; - #endif err_t err = tcp_output(_pcb); @@ -621,7 +610,7 @@ bool AsyncClient::send() _pcb_sent_at = millis(); _tx_unacked_len += _tx_unsent_len; _tx_unsent_len = 0; - + return true; } @@ -662,7 +651,7 @@ void AsyncClient::_connected(std::shared_ptr& errorTracker, void { ATCP_LOGDEBUG3("_connected: ID =", errorTracker->getConnectionId(), ", _pcb =", ((NULL == _pcb) ? "NULL" : "OK") ); ATCP_LOGDEBUG3("errorToString =", errorToString(err), ", err =", err ); - + errorTracker->setCloseError(err); errorTracker->setErrored(EE_CONNECTED_CB); _pcb = reinterpret_cast(pcb); @@ -682,22 +671,21 @@ void AsyncClient::_connected(std::shared_ptr& errorTracker, void { _pcb_busy = false; _rx_last_packet = millis(); - + //tcp_setprio(_pcb, TCP_PRIO_MIN); tcp_setprio(_pcb, TCP_PRIO_NORMAL); - + tcp_recv(_pcb, &_s_recv); tcp_sent(_pcb, &_s_sent); tcp_poll(_pcb, &_s_poll, 1); #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure) { if (tcp_ssl_new_client(_pcb) < 0) { _close(); - + return; } @@ -727,12 +715,10 @@ void AsyncClient::_close() if (_pcb) { #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure) { tcp_ssl_free(_pcb); } - #endif clearTcpCallbacks(_pcb); @@ -745,7 +731,7 @@ void AsyncClient::_close() else { ATCP_LOGDEBUG3("_close : ID =", getConnectionId(), ", abort() called for AsyncClient 0x", uintptr_t(this)); - + abort(); } @@ -768,12 +754,10 @@ void AsyncClient::_error(err_t err) if (_pcb) { #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure) { tcp_ssl_free(_pcb); } - #endif // At this callback _pcb is possible already freed. Thus, no calls are @@ -782,7 +766,7 @@ void AsyncClient::_error(err_t err) clearTcpCallbacks(_pcb); tcp_close(_pcb); ////// - + _pcb = NULL; } @@ -808,12 +792,10 @@ void AsyncClient::_ssl_error(int8_t err) void AsyncClient::_sent(std::shared_ptr& errorTracker, tcp_pcb* pcb, uint16_t len) { ASYNCTCP_RP2040W_UNUSED(pcb); - + #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure && !_handshake_done) return; - #endif _rx_last_packet = millis(); @@ -854,7 +836,7 @@ void AsyncClient::_recv(std::shared_ptr& errorTracker, tcp_pcb* { ATCP_LOGDEBUG3("_recv: ID =", errorTracker->getConnectionId(), ", _pcb =", ((NULL == _pcb) ? "NULL" : "OK") ); ATCP_LOGDEBUG3("errorToString =", errorToString(err), ", err =", err ); - + errorTracker->setCloseError(err); errorTracker->setErrored(EE_RECV_CB); _pcb = pcb; @@ -903,7 +885,6 @@ void AsyncClient::_recv(std::shared_ptr& errorTracker, tcp_pcb* errorTracker->setCloseError(ERR_OK); #if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure) { ATCP_LOGDEBUG3("_recv: ID =", getConnectionId(), "pb->tot_len =", pb->tot_len); @@ -922,7 +903,6 @@ void AsyncClient::_recv(std::shared_ptr& errorTracker, tcp_pcb* return; } - #endif while (pb != NULL) @@ -933,7 +913,7 @@ void AsyncClient::_recv(std::shared_ptr& errorTracker, tcp_pcb* if (!errorTracker->hasClient()) { - while (pb != NULL) + while (pb != NULL) { pbuf *b = pb; pb = b->next; @@ -1015,7 +995,6 @@ void AsyncClient::_poll(std::shared_ptr& errorTracker, tcp_pcb* } #if ASYNC_TCP_SSL_ENABLED - // SSL Handshake Timeout if (_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= 2000) { @@ -1023,7 +1002,6 @@ void AsyncClient::_poll(std::shared_ptr& errorTracker, tcp_pcb* return; } - #endif // Everything is fine @@ -1036,9 +1014,9 @@ void AsyncClient::_poll(std::shared_ptr& errorTracker, tcp_pcb* ///////////////////////////////////////////////// #if LWIP_VERSION_MAJOR == 1 - void AsyncClient::_dns_found(struct ip_addr *ipaddr) +void AsyncClient::_dns_found(struct ip_addr *ipaddr) #else - void AsyncClient::_dns_found(ip_addr_t *p) +void AsyncClient::_dns_found(ip_addr_t *p) #endif { if (p) @@ -1063,9 +1041,9 @@ void AsyncClient::_poll(std::shared_ptr& errorTracker, tcp_pcb* // lwIP Callbacks #if LWIP_VERSION_MAJOR == 1 - void AsyncClient::_s_dns_found(const char *name, const ip_addr *ipaddr, void *arg) +void AsyncClient::_s_dns_found(const char *name, const ip_addr *ipaddr, void *arg) #else - void AsyncClient::_s_dns_found(const char *name, ip_addr_t *p, void *arg) +void AsyncClient::_s_dns_found(const char *name, ip_addr_t *p, void *arg) #endif { ASYNCTCP_RP2040W_UNUSED(name); @@ -1076,9 +1054,9 @@ void AsyncClient::_poll(std::shared_ptr& errorTracker, tcp_pcb* err_t AsyncClient::_s_poll(void *arg, struct tcp_pcb *tpcb) { - AsyncClient *c = reinterpret_cast(arg); + AsyncClient *c = reinterpret_cast(arg); std::shared_ptrerrorTracker = c->getACErrorTracker(); - + c->_poll(errorTracker, tpcb); return errorTracker->getCallbackCloseError(); @@ -1090,7 +1068,7 @@ err_t AsyncClient::_s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err { AsyncClient *c = reinterpret_cast(arg); auto errorTracker = c->getACErrorTracker(); - + c->_recv(errorTracker, tpcb, pb, err); return errorTracker->getCallbackCloseError(); @@ -1102,7 +1080,7 @@ void AsyncClient::_s_error(void *arg, err_t err) { AsyncClient *c = reinterpret_cast(arg); auto errorTracker = c->getACErrorTracker(); - + errorTracker->setCloseError(err); errorTracker->setErrored(EE_ERROR_CB); c->_error(err); @@ -1114,7 +1092,7 @@ err_t AsyncClient::_s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len) { AsyncClient *c = reinterpret_cast(arg); auto errorTracker = c->getACErrorTracker(); - + c->_sent(errorTracker, tpcb, len); return errorTracker->getCallbackCloseError(); @@ -1126,7 +1104,7 @@ err_t AsyncClient::_s_connected(void* arg, void* tpcb, err_t err) { AsyncClient *c = reinterpret_cast(arg); auto errorTracker = c->getACErrorTracker(); - + c->_connected(errorTracker, tpcb, err); return errorTracker->getCallbackCloseError(); @@ -1176,10 +1154,10 @@ AsyncClient & AsyncClient::operator+=(const AsyncClient &other) else { AsyncClient *c = next; - - while (c->next != NULL) + + while (c->next != NULL) c = c->next; - + c->next = (AsyncClient*)(&other); c->next->prev = c; } @@ -1244,7 +1222,7 @@ uint16_t AsyncClient::getMss() { if (_pcb) return tcp_mss(_pcb); - + return 0; } @@ -1502,7 +1480,6 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg) size_t AsyncClient::space() { #if ASYNC_TCP_SSL_ENABLED - if ( (_pcb != NULL) && (_pcb->state == ESTABLISHED) && _handshake_done ) { uint16_t s = tcp_sndbuf(_pcb); @@ -1512,7 +1489,6 @@ size_t AsyncClient::space() #ifdef AXTLS_2_0_0_SNDBUF return tcp_ssl_sndbuf(_pcb); #else - if (s >= 128) //safe approach return s - 128; @@ -1522,14 +1498,11 @@ size_t AsyncClient::space() return s; } - #else // ASYNC_TCP_SSL_ENABLED - if ((_pcb != NULL) && (_pcb->state == ESTABLISHED)) { return tcp_sndbuf(_pcb); } - #endif // ASYNC_TCP_SSL_ENABLED return 0; @@ -1554,58 +1527,41 @@ const char * AsyncClient::errorToString(err_t error) { switch (error) { - case ERR_OK: + case ERR_OK: return "OK"; - - case ERR_MEM: + case ERR_MEM: return "Out of memory error"; - - case ERR_BUF: + case ERR_BUF: return "Buffer error"; - - case ERR_TIMEOUT: + case ERR_TIMEOUT: return "Timeout"; - - case ERR_RTE: + case ERR_RTE: return "Routing problem"; - - case ERR_INPROGRESS: + case ERR_INPROGRESS: return "Operation in progress"; - - case ERR_VAL: + case ERR_VAL: return "Illegal value"; - - case ERR_WOULDBLOCK: + case ERR_WOULDBLOCK: return "Operation would block"; - - case ERR_USE: + case ERR_USE: return "Address in use"; - - case ERR_ALREADY: + case ERR_ALREADY: return "Already connected"; - - case ERR_CONN: + case ERR_CONN: return "Not connected"; - - case ERR_IF: + case ERR_IF: return "Low-level netif error"; - - case ERR_ABRT: + case ERR_ABRT: return "Connection aborted"; - - case ERR_RST: + case ERR_RST: return "Connection reset"; - case ERR_CLSD: return "Connection closed"; - - case ERR_ARG: + case ERR_ARG: return "Illegal argument"; - - case -55: + case -55: return "DNS failed"; - - default: + default: return "UNKNOWN"; } } @@ -1613,9 +1569,9 @@ const char * AsyncClient::errorToString(err_t error) ///////////////////////////////////////////////// /***************************************************** - // Defined in ./pico-sdk/lib/lwip/src/include/lwip/tcpbase.h - enum tcp_state - { +// Defined in ./pico-sdk/lib/lwip/src/include/lwip/tcpbase.h +enum tcp_state +{ CLOSED = 0, LISTEN = 1, SYN_SENT = 2, @@ -1627,47 +1583,36 @@ const char * AsyncClient::errorToString(err_t error) CLOSING = 8, LAST_ACK = 9, TIME_WAIT = 10 - }; +}; *****************************************************/ const char * AsyncClient::stateToString() { switch (state()) { - case CLOSED: + case CLOSED: return "Closed"; - - case LISTEN: + case LISTEN: return "Listen"; - - case SYN_SENT: + case SYN_SENT: return "SYN Sent"; - - case SYN_RCVD: + case SYN_RCVD: return "SYN Received"; - - case ESTABLISHED: + case ESTABLISHED: return "Established"; - - case FIN_WAIT_1: + case FIN_WAIT_1: return "FIN Wait 1"; - - case FIN_WAIT_2: + case FIN_WAIT_2: return "FIN Wait 2"; - - case CLOSE_WAIT: + case CLOSE_WAIT: return "Close Wait"; - - case CLOSING: + case CLOSING: return "Closing"; - - case LAST_ACK: + case LAST_ACK: return "Last ACK"; - - case TIME_WAIT: + case TIME_WAIT: return "Time Wait"; - - default: + default: return "UNKNOWN"; } } @@ -1702,10 +1647,8 @@ AsyncServer::AsyncServer(IPAddress addr, uint16_t port) #endif { #ifdef DEBUG_MORE - for (size_t i = 0; i < EE_MAX; ++i) _event_count[i] = 0; - #endif } @@ -1726,10 +1669,8 @@ AsyncServer::AsyncServer(uint16_t port) #endif { #ifdef DEBUG_MORE - for (size_t i = 0; i < EE_MAX; ++i) _event_count[i] = 0; - #endif } @@ -1775,7 +1716,7 @@ void AsyncServer::begin() //tcp_setprio(_pcb, TCP_PRIO_MIN); tcp_setprio(_pcb, TCP_PRIO_NORMAL); - + ip_addr_t local_addr; local_addr.addr = (uint32_t) _addr; err = tcp_bind(pcb, &local_addr, _port); @@ -1784,7 +1725,7 @@ void AsyncServer::begin() if (err != ERR_OK) { tcp_close(pcb); - + return; } @@ -1793,7 +1734,7 @@ void AsyncServer::begin() if (!listen_pcb) { tcp_close(pcb); - + return; } @@ -1841,7 +1782,6 @@ void AsyncServer::end() } #if ASYNC_TCP_SSL_ENABLED - if (_ssl_ctx) { ssl_ctx_free(_ssl_ctx); @@ -1865,7 +1805,6 @@ void AsyncServer::end() } } } - #endif } @@ -1915,7 +1854,6 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) if (_connect_cb) { #if ASYNC_TCP_SSL_ENABLED - if (_noDelay || _ssl_ctx) #else if (_noDelay) @@ -1925,8 +1863,7 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) tcp_nagle_enable(pcb); #if ASYNC_TCP_SSL_ENABLED - - if (_ssl_ctx) + if (_ssl_ctx) { if (tcp_ssl_has_client() || _pending) { @@ -1939,7 +1876,7 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) if (tcp_close(pcb) != ERR_OK) { tcp_abort(pcb); - + return ERR_ABRT; } @@ -1951,10 +1888,10 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) new_item->pcb = pcb; new_item->pb = NULL; new_item->next = NULL; - + //tcp_setprio(_pcb, TCP_PRIO_MIN); tcp_setprio(_pcb, TCP_PRIO_NORMAL); - + tcp_arg(pcb, this); tcp_poll(pcb, &_s_poll, 1); tcp_recv(pcb, &_s_recv); @@ -1993,7 +1930,7 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) if (tcp_close(pcb) != ERR_OK) { tcp_abort(pcb); - + return ERR_ABRT; } } @@ -2011,7 +1948,7 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) if (c) { auto errorTracker = c->getACErrorTracker(); - + #ifdef DEBUG_MORE errorTracker->onErrorEvent([](void *obj, size_t ee) { @@ -2028,25 +1965,23 @@ err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err) else { ATCP_LOGDEBUG("_accept: new AsyncClient() failed, connection aborted!"); - + if (tcp_close(pcb) != ERR_OK) { tcp_abort(pcb); - + return ERR_ABRT; } } - #if ASYNC_TCP_SSL_ENABLED } - #endif } if (tcp_close(pcb) != ERR_OK) { tcp_abort(pcb); - + return ERR_ABRT; } @@ -2105,7 +2040,6 @@ err_t AsyncServer::_poll(tcp_pcb* pcb) // Should there be error handling for when "new AsynClient" fails?? free(p); } - return ERR_OK; } @@ -2152,7 +2086,7 @@ err_t AsyncServer::_recv(struct tcp_pcb *pcb, struct pbuf *pb, err_t err) if (err != ERR_OK) { tcp_abort(pcb); - + return ERR_ABRT; } @@ -2217,7 +2151,7 @@ err_t AsyncServer::_s_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *pb, err_ return reinterpret_cast(arg)->_recv(pcb, pb, err); } -#endif // #if ASYNC_TCP_SSL_ENABLED +#endif // #if ASYNC_TCP_SSL_ENABLED ///////////////////////////////////////////////// diff --git a/src/AsyncTCP_RP2040W.h b/src/AsyncTCP_RP2040W.h index a2a0fc6..0d20169 100644 --- a/src/AsyncTCP_RP2040W.h +++ b/src/AsyncTCP_RP2040W.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** AsyncTCP_RP2040W.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -49,7 +50,7 @@ ///////////////////////////////////////////// #if ( defined(ARDUINO_RASPBERRY_PI_PICO_W) ) - + #if (_ASYNCTCP_RP2040W_LOGLEVEL_ > 2) #if defined(ARDUINO_RASPBERRY_PI_PICO_W) #warning RASPBERRY_PI_PICO_W board using CYW4343 WiFi selected @@ -62,7 +63,7 @@ #undef WIFI_USE_RP2040 #endif #define WIFI_USE_RP2040 true - + #if (_ASYNCTCP_RP2040W_LOGLEVEL_ > 2) #warning Use RP2040 architecture from WiFiWebServer #endif @@ -70,7 +71,7 @@ #else #error For RASPBERRY_PI_PICO_W board using CYW43439 WiFi only - + #endif ///////////////////////////////////////////// @@ -84,20 +85,20 @@ ///////////////////////////////////////////// -#define ASYNCTCP_RP2040W_VERSION "AsyncTCP_RP2040W v1.1.0" +#define ASYNCTCP_RP2040W_VERSION "AsyncTCP_RP2040W v1.2.0" #define ASYNCTCP_RP2040W_VERSION_MAJOR 1 -#define ASYNCTCP_RP2040W_VERSION_MINOR 1 +#define ASYNCTCP_RP2040W_VERSION_MINOR 2 #define ASYNCTCP_RP2040W_VERSION_PATCH 0 -#define ASYNCTCP_RP2040W_VERSION_INT 1001000 +#define ASYNCTCP_RP2040W_VERSION_INT 1002000 ///////////////////////////////////////////// #if ASYNC_TCP_SSL_ENABLED #undef ASYNC_TCP_SSL_ENABLED - #define ASYNC_TCP_SSL_ENABLED false - + #define ASYNC_TCP_SSL_ENABLED false + #warning ASYNC_TCP_SSL_ENABLED is not ready yet. Disable it #endif @@ -114,10 +115,10 @@ extern "C" { -#include "lwip/ip_addr.h" -#include "lwip/err.h" -#include "lwip/tcp.h" -#include "lwip/pbuf.h" + #include "lwip/ip_addr.h" + #include "lwip/err.h" + #include "lwip/tcp.h" + #include "lwip/pbuf.h" }; #ifndef ASYNCTCP_RP2040W_UNUSED @@ -153,7 +154,7 @@ typedef std::function AcPacketHandle typedef std::function AcTimeoutHandler; typedef std::function AsNotifyHandler; -enum error_events +enum error_events { EE_OK = 0, EE_ABORTED, // Callback or foreground aborted connections @@ -169,13 +170,13 @@ enum error_events // DEBUG_MORE is for gathering more information on which CBs close events are // occuring and count. // #define DEBUG_MORE 1 -class ACErrorTracker +class ACErrorTracker { private: AsyncClient *_client; err_t _close_error; int _errored; - + #if DEBUG_ESP_ASYNC_TCP size_t _connectionId; #endif @@ -188,18 +189,18 @@ class ACErrorTracker protected: friend class AsyncClient; friend class AsyncServer; - + #ifdef DEBUG_MORE void onErrorEvent(AsNotifyHandler cb, void *arg); #endif #if DEBUG_ESP_ASYNC_TCP - void setConnectionId(size_t id) + void setConnectionId(size_t id) { _connectionId = id; } - - size_t getConnectionId() + + size_t getConnectionId() { return _connectionId; } @@ -208,31 +209,30 @@ class ACErrorTracker void setCloseError(err_t e); void setErrored(size_t errorEvent); err_t getCallbackCloseError(); - - void clearClient() + + void clearClient() { - if (_client) - _client = NULL; + if (_client) _client = NULL; } public: - err_t getCloseError() const + err_t getCloseError() const { return _close_error; } - - bool hasClient() const + + bool hasClient() const { return (_client != NULL); } - + ACErrorTracker(AsyncClient *c); ~ACErrorTracker() {} }; ///////////////////////////////////////////////// -class AsyncClient +class AsyncClient { protected: friend class AsyncTCPbuffer; @@ -255,7 +255,7 @@ class AsyncClient AcConnectHandler _poll_cb; void* _poll_cb_arg; bool _pcb_busy; - + #if ASYNC_TCP_SSL_ENABLED bool _pcb_secure; bool _handshake_done; @@ -278,14 +278,14 @@ class AsyncClient void _close(); void _connected(std::shared_ptr& closeAbort, void* pcb, err_t err); void _error(err_t err); - + #if ASYNC_TCP_SSL_ENABLED void _ssl_error(int8_t err); #endif void _poll(std::shared_ptr& closeAbort, tcp_pcb* pcb); void _sent(std::shared_ptr& closeAbort, tcp_pcb* pcb, uint16_t len); - + #if LWIP_VERSION_MAJOR == 1 void _dns_found(struct ip_addr *ipaddr); #else @@ -297,7 +297,7 @@ class AsyncClient static void _s_error(void *arg, err_t err); static err_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); static err_t _s_connected(void* arg, void* tpcb, err_t err); - + #if LWIP_VERSION_MAJOR == 1 static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); #else @@ -310,12 +310,12 @@ class AsyncClient static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err); #endif - std::shared_ptr getACErrorTracker() const + std::shared_ptr getACErrorTracker() const { return _errorTracker; }; - - void setCloseError(err_t e) const + + void setCloseError(err_t e) const { _errorTracker->setCloseError(e); } @@ -337,11 +337,11 @@ class AsyncClient bool operator==(const AsyncClient &other); - bool operator!=(const AsyncClient &other) + bool operator!=(const AsyncClient &other) { return !(*this == other); } - + #if ASYNC_TCP_SSL_ENABLED bool connect(IPAddress ip, uint16_t port, bool secure = false); bool connect(const char* host, uint16_t port, bool secure = false); @@ -360,19 +360,19 @@ class AsyncClient size_t add(const char* data, size_t size, uint8_t apiflags = 0); //add for sending bool send();//send all data added with the method above size_t ack(size_t len); //ack data that you have not acked using the method below - - void ackLater() + + void ackLater() { _ack_pcb = false; //will not ack the current packet. Call from onData } - - bool isRecvPush() + + bool isRecvPush() { return !!(_recv_pbuf_flags & PBUF_FLAG_PUSH); } - + #if DEBUG_ESP_ASYNC_TCP - size_t getConnectionId() const + size_t getConnectionId() const { return _errorTracker->getConnectionId(); } @@ -423,8 +423,8 @@ class AsyncClient const char * stateToString(); void _recv(std::shared_ptr& closeAbort, tcp_pcb* pcb, pbuf* pb, err_t err); - - err_t getCloseError() const + + err_t getCloseError() const { return _errorTracker->getCloseError(); } @@ -439,7 +439,7 @@ class AsyncClient ///////////////////////////////////////////////// -class AsyncServer +class AsyncServer { protected: uint16_t _port; @@ -448,7 +448,7 @@ class AsyncServer tcp_pcb* _pcb; AcConnectHandler _connect_cb; void* _connect_cb_arg; - + #if ASYNC_TCP_SSL_ENABLED struct pending_pcb * _pending; SSL_CTX * _ssl_ctx; @@ -466,7 +466,7 @@ class AsyncServer AsyncServer(uint16_t port); ~AsyncServer(); void onClient(AcConnectHandler cb, void* arg); - + #if ASYNC_TCP_SSL_ENABLED void onSslFileRequest(AcSSlFileHandler cb, void* arg); void beginSecure(const char *cert, const char *private_key_file, const char *password); @@ -477,9 +477,9 @@ class AsyncServer void setNoDelay(bool nodelay); bool getNoDelay(); uint8_t status(); - + #ifdef DEBUG_MORE - int getEventCount(size_t ee) const + int getEventCount(size_t ee) const { return _event_count[ee]; } @@ -488,9 +488,9 @@ class AsyncServer protected: err_t _accept(tcp_pcb* newpcb, err_t err); static err_t _s_accept(void *arg, tcp_pcb* newpcb, err_t err); - + #ifdef DEBUG_MORE - int incEventCount(size_t ee) + int incEventCount(size_t ee) { return ++_event_count[ee]; } diff --git a/src/AsyncTCP_RP2040W_Debug.h b/src/AsyncTCP_RP2040W_Debug.h index cd6a201..ae55598 100644 --- a/src/AsyncTCP_RP2040W_Debug.h +++ b/src/AsyncTCP_RP2040W_Debug.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** AsyncTCP_RP2040W_Debug.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ #pragma once diff --git a/src/AsyncTCP_RP2040W_buffer.cpp b/src/AsyncTCP_RP2040W_buffer.cpp index 67ede4c..2689c72 100644 --- a/src/AsyncTCP_RP2040W_buffer.cpp +++ b/src/AsyncTCP_RP2040W_buffer.cpp @@ -1,50 +1,51 @@ /**************************************************************************************************************************** AsyncTCP_RP2040W_buffer.cpp - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /** - @file AsyncTCP_RP2040W_buffer.cpp - @date 22.01.2016 - @author Markus Sattler - - Copyright (c) 2015 Markus Sattler. All rights reserved. - This file is part of the Asynv TCP for ESP. - - 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 - -*/ + * @file AsyncTCP_RP2040W_buffer.cpp + * @date 22.01.2016 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the Asynv TCP for ESP. + * + * 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 @@ -58,7 +59,7 @@ ///////////////////////////////////////////////////////// -AsyncTCPbuffer::AsyncTCPbuffer(AsyncClient* client) +AsyncTCPbuffer::AsyncTCPbuffer(AsyncClient* client) { if (client == NULL) { @@ -84,65 +85,65 @@ AsyncTCPbuffer::AsyncTCPbuffer(AsyncClient* client) ///////////////////////////////////////////////////////// -AsyncTCPbuffer::~AsyncTCPbuffer() +AsyncTCPbuffer::~AsyncTCPbuffer() { - if (_client) + if (_client) { _client->close(); } - if (_RXbuffer) + if (_RXbuffer) { delete _RXbuffer; _RXbuffer = NULL; } - if (_TXbufferWrite) + if (_TXbufferWrite) { // will be deleted in _TXbufferRead chain _TXbufferWrite = NULL; } - if (_TXbufferRead) + if (_TXbufferRead) { cbuf * next = _TXbufferRead->next; delete _TXbufferRead; - - while (next != NULL) + + while (next != NULL) { _TXbufferRead = next; next = _TXbufferRead->next; delete _TXbufferRead; } - + _TXbufferRead = NULL; } } ///////////////////////////////////////////////////////// -size_t AsyncTCPbuffer::write(String & data) +size_t AsyncTCPbuffer::write(String & data) { return write(data.c_str(), data.length()); } ///////////////////////////////////////////////////////// -size_t AsyncTCPbuffer::write(uint8_t data) +size_t AsyncTCPbuffer::write(uint8_t data) { return write(&data, 1); } ///////////////////////////////////////////////////////// -size_t AsyncTCPbuffer::write(const char* data) +size_t AsyncTCPbuffer::write(const char* data) { return write((const uint8_t *) data, strlen(data)); } ///////////////////////////////////////////////////////// -size_t AsyncTCPbuffer::write(const char *data, size_t len) +size_t AsyncTCPbuffer::write(const char *data, size_t len) { return write((const uint8_t *) data, len); } @@ -155,40 +156,40 @@ size_t AsyncTCPbuffer::write(const char *data, size_t len) @param len @return */ -size_t AsyncTCPbuffer::write(const uint8_t *data, size_t len) +size_t AsyncTCPbuffer::write(const uint8_t *data, size_t len) { - if (_TXbufferWrite == NULL || _client == NULL || !_client->connected() || data == NULL || len == 0) + if (_TXbufferWrite == NULL || _client == NULL || !_client->connected() || data == NULL || len == 0) { return 0; } size_t bytesLeft = len; - - while (bytesLeft) + + while (bytesLeft) { size_t w = _TXbufferWrite->write((const char*) data, bytesLeft); bytesLeft -= w; data += w; - + _sendBuffer(); // add new buffer since we have more data - if (_TXbufferWrite->full() && bytesLeft > 0) + if (_TXbufferWrite->full() && bytesLeft > 0) { /* - // to less ram!!! - if(ESP.getFreeHeap() < 4096) { + // to less ram!!! + if(ESP.getFreeHeap() < 4096) { ATCP_LOGDEBUG("run out of Heap can not send all Data!"); return (len - bytesLeft); - } + } */ cbuf * next = new (std::nothrow) cbuf(TCP_MSS); - + if (next == NULL) { ATCP_LOGDEBUG("run out of Heap!"); panic(); - } + } else { ATCP_LOGDEBUG("new cbuf"); @@ -211,32 +212,31 @@ size_t AsyncTCPbuffer::write(const uint8_t *data, size_t len) /** wait until all data has send out */ -void AsyncTCPbuffer::flush() +void AsyncTCPbuffer::flush() { - while (!_TXbufferWrite->empty()) + while (!_TXbufferWrite->empty()) { - while (connected() && !_client->canSend()) + while (connected() && !_client->canSend()) { delay(0); } - + if (!connected()) return; - _sendBuffer(); } } ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::noCallback() +void AsyncTCPbuffer::noCallback() { _RXmode = ATB_RX_MODE_NONE; } ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbufferDoneCb done) +void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbufferDoneCb done) { if (_client == NULL) { @@ -244,7 +244,7 @@ void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbuff } ATCP_LOGDEBUG1("readStringUntil terminator:", terminator); - + _RXmode = ATB_RX_MODE_NONE; _cbDone = done; _rxReadStringPtr = str; @@ -256,7 +256,7 @@ void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbuff ///////////////////////////////////////////////////////// /* - void AsyncTCPbuffer::readBytesUntil(char terminator, char *buffer, size_t length, AsyncTCPbufferDoneCb done) + void AsyncTCPbuffer::readBytesUntil(char terminator, char *buffer, size_t length, AsyncTCPbufferDoneCb done) { _RXmode = ATB_RX_MODE_NONE; _cbDone = done; @@ -267,7 +267,7 @@ void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbuff _handleRxBuffer(NULL, 0); } - void AsyncTCPbuffer::readBytesUntil(char terminator, uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done) + void AsyncTCPbuffer::readBytesUntil(char terminator, uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done) { readBytesUntil(terminator, (char *) buffer, length, done); } @@ -275,9 +275,9 @@ void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbuff ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::readBytes(char *buffer, size_t length, AsyncTCPbufferDoneCb done) +void AsyncTCPbuffer::readBytes(char *buffer, size_t length, AsyncTCPbufferDoneCb done) { - if (_client == NULL) + if (_client == NULL) { return; } @@ -292,16 +292,16 @@ void AsyncTCPbuffer::readBytes(char *buffer, size_t length, AsyncTCPbufferDoneCb ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::readBytes(uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done) +void AsyncTCPbuffer::readBytes(uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done) { readBytes((char *) buffer, length, done); } ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::onData(AsyncTCPbufferDataCb cb) +void AsyncTCPbuffer::onData(AsyncTCPbufferDataCb cb) { - if (_client == NULL) + if (_client == NULL) { return; } @@ -316,63 +316,63 @@ void AsyncTCPbuffer::onData(AsyncTCPbufferDataCb cb) ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::onDisconnect(AsyncTCPbufferDisconnectCb cb) +void AsyncTCPbuffer::onDisconnect(AsyncTCPbufferDisconnectCb cb) { _cbDisconnect = cb; } ///////////////////////////////////////////////////////// -IPAddress AsyncTCPbuffer::remoteIP() +IPAddress AsyncTCPbuffer::remoteIP() { - if (!_client) + if (!_client) { return IPAddress(0, 0, 0, 0); } - + return _client->remoteIP(); } ///////////////////////////////////////////////////////// -uint16_t AsyncTCPbuffer::remotePort() +uint16_t AsyncTCPbuffer::remotePort() { - if (!_client) + if (!_client) { return 0; } - + return _client->remotePort(); } ///////////////////////////////////////////////////////// -bool AsyncTCPbuffer::connected() +bool AsyncTCPbuffer::connected() { - if (!_client) + if (!_client) { return false; } - + return _client->connected(); } ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::stop() +void AsyncTCPbuffer::stop() { - if (!_client) + if (!_client) { return; } - + _client->stop(); _client = NULL; - if (_cbDone) + if (_cbDone) { - switch (_RXmode) + switch (_RXmode) { case ATB_RX_MODE_READ_BYTES: case ATB_RX_MODE_TERMINATOR: @@ -380,18 +380,17 @@ void AsyncTCPbuffer::stop() _RXmode = ATB_RX_MODE_NONE; _cbDone(false, NULL); break; - default: break; } } - + _RXmode = ATB_RX_MODE_NONE; } ///////////////////////////////////////////////////////// -void AsyncTCPbuffer::close() +void AsyncTCPbuffer::close() { stop(); } @@ -401,31 +400,31 @@ void AsyncTCPbuffer::close() /** attachCallbacks to AsyncClient class */ -void AsyncTCPbuffer::_attachCallbacks() +void AsyncTCPbuffer::_attachCallbacks() { - if (!_client) + if (!_client) { return; } ATCP_LOGDEBUG("attachCallbacks"); - _client->onPoll([](void *obj, AsyncClient * c) + _client->onPoll([](void *obj, AsyncClient * c) { ASYNCTCP_RP2040W_UNUSED(c); AsyncTCPbuffer* b = ((AsyncTCPbuffer*)(obj)); - - if ((b->_TXbufferRead != NULL) && !b->_TXbufferRead->empty()) + + if ((b->_TXbufferRead != NULL) && !b->_TXbufferRead->empty()) { b->_sendBuffer(); } - + // if(!b->_RXbuffer->empty()) { // b->_handleRxBuffer(NULL, 0); // } }, this); - _client->onAck([](void *obj, AsyncClient * c, size_t len, uint32_t time) + _client->onAck([](void *obj, AsyncClient * c, size_t len, uint32_t time) { ASYNCTCP_RP2040W_UNUSED(c); ASYNCTCP_RP2040W_UNUSED(len); @@ -440,28 +439,28 @@ void AsyncTCPbuffer::_attachCallbacks() AsyncTCPbuffer* b = ((AsyncTCPbuffer*)(obj)); b->_client = NULL; bool del = true; - - if (b->_cbDisconnect) + + if (b->_cbDisconnect) { del = b->_cbDisconnect(b); } - + delete c; - - if (del) + + if (del) { delete b; } }, this); - _client->onData([](void *obj, AsyncClient * c, void *buf, size_t len) + _client->onData([](void *obj, AsyncClient * c, void *buf, size_t len) { ASYNCTCP_RP2040W_UNUSED(c); AsyncTCPbuffer* b = ((AsyncTCPbuffer*)(obj)); b->_rxData((uint8_t *)buf, len); }, this); - _client->onTimeout([](void *obj, AsyncClient * c, uint32_t time) + _client->onTimeout([](void *obj, AsyncClient * c, uint32_t time) { ASYNCTCP_RP2040W_UNUSED(obj); ASYNCTCP_RP2040W_UNUSED(time); @@ -479,31 +478,31 @@ void AsyncTCPbuffer::_attachCallbacks() /** send TX buffer if possible */ -void AsyncTCPbuffer::_sendBuffer() +void AsyncTCPbuffer::_sendBuffer() { //ATCP_LOGDEBUG("_sendBuffer..."); size_t available = _TXbufferRead->available(); - - if (available == 0 || _client == NULL || !_client->connected() || !_client->canSend()) + + if (available == 0 || _client == NULL || !_client->connected() || !_client->canSend()) { return; } - while (connected() && (_client->space() > 0) && (_TXbufferRead->available() > 0) && _client->canSend()) + while (connected() && (_client->space() > 0) && (_TXbufferRead->available() > 0) && _client->canSend()) { available = _TXbufferRead->available(); - if (available > _client->space()) + if (available > _client->space()) { available = _client->space(); } char *out = new (std::nothrow) char[available]; - + if (out == NULL) { ATCP_LOGDEBUG("to less heap, try later."); - + return; } @@ -512,12 +511,12 @@ void AsyncTCPbuffer::_sendBuffer() // send data size_t send = _client->write((const char*) out, available); - + if (send != available) { ATCP_LOGDEBUG3("_sendBuffer write failed send:", send, ", available:", available); - - if (!connected()) + + if (!connected()) { ATCP_LOGDEBUG("incomplete transfer, connection lost."); } @@ -527,12 +526,12 @@ void AsyncTCPbuffer::_sendBuffer() _TXbufferRead->remove(send); // if buffer is empty and there is a other buffer in chain delete the empty one - if (_TXbufferRead->available() == 0 && _TXbufferRead->next != NULL) + if (_TXbufferRead->available() == 0 && _TXbufferRead->next != NULL) { cbuf * old = _TXbufferRead; _TXbufferRead = _TXbufferRead->next; delete old; - + ATCP_LOGDEBUG("delete cbuf"); } @@ -548,15 +547,15 @@ void AsyncTCPbuffer::_sendBuffer() @param buf @param len */ -void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) +void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) { - if (!_client || !_client->connected()) + if (!_client || !_client->connected()) { ATCP_LOGDEBUG("not connected!"); return; } - - if (!_RXbuffer) + + if (!_RXbuffer) { ATCP_LOGDEBUG("_rxData no _RXbuffer!"); return; @@ -566,16 +565,16 @@ void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) size_t handled = 0; - if (_RXmode != ATB_RX_MODE_NONE) + if (_RXmode != ATB_RX_MODE_NONE) { handled = _handleRxBuffer((uint8_t *) buf, len); buf += handled; len -= handled; // handle as much as possible before using the buffer - if (_RXbuffer->empty()) + if (_RXbuffer->empty()) { - while (_RXmode != ATB_RX_MODE_NONE && handled != 0 && len > 0) + while (_RXmode != ATB_RX_MODE_NONE && handled != 0 && len > 0) { handled = _handleRxBuffer(buf, len); buf += handled; @@ -584,7 +583,7 @@ void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) } } - if (len > 0) + if (len > 0) { if (_RXbuffer->room() < len) @@ -593,7 +592,7 @@ void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) ATCP_LOGDEBUG("_rxData buffer full try resize"); _RXbuffer->resizeAdd((len + _RXbuffer->room())); - if (_RXbuffer->room() < len) + if (_RXbuffer->room() < len) { ATCP_LOGDEBUG1("_rxData buffer to full can only handle:", _RXbuffer->room()); } @@ -602,19 +601,19 @@ void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) _RXbuffer->write((const char *) (buf), len); } - if (!_RXbuffer->empty() && _RXmode != ATB_RX_MODE_NONE) + if (!_RXbuffer->empty() && _RXmode != ATB_RX_MODE_NONE) { // handle as much as possible data in buffer handled = _handleRxBuffer(NULL, 0); - - while (_RXmode != ATB_RX_MODE_NONE && handled != 0) + + while (_RXmode != ATB_RX_MODE_NONE && handled != 0) { handled = _handleRxBuffer(NULL, 0); } } // clean up ram - if (_RXbuffer->empty() && _RXbuffer->room() != 100) + if (_RXbuffer->empty() && _RXbuffer->room() != 100) { _RXbuffer->resize(100); } @@ -622,9 +621,9 @@ void AsyncTCPbuffer::_rxData(uint8_t *buf, size_t len) ///////////////////////////////////////////////////////// -size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t *buf, size_t len) +size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t *buf, size_t len) { - if (!_client || !_client->connected() || _RXbuffer == NULL) + if (!_client || !_client->connected() || _RXbuffer == NULL) { return 0; } @@ -634,73 +633,73 @@ size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t *buf, size_t len) size_t BufferAvailable = _RXbuffer->available(); size_t r = 0; - if (_RXmode == ATB_RX_MODE_NONE) + if (_RXmode == ATB_RX_MODE_NONE) { return 0; - } - else if (_RXmode == ATB_RX_MODE_FREE) + } + else if (_RXmode == ATB_RX_MODE_FREE) { - if (_cbRX == NULL) + if (_cbRX == NULL) { return 0; } - if (BufferAvailable > 0) + if (BufferAvailable > 0) { uint8_t * b = new (std::nothrow) uint8_t[BufferAvailable]; - - if (b == NULL) + + if (b == NULL) { panic(); //TODO: What action should this be ? } - + _RXbuffer->peek((char *) b, BufferAvailable); r = _cbRX(b, BufferAvailable); _RXbuffer->remove(r); } - if (r == BufferAvailable && buf && (len > 0)) + if (r == BufferAvailable && buf && (len > 0)) { return _cbRX(buf, len); - } - else + } + else { return 0; } - } - else if (_RXmode == ATB_RX_MODE_READ_BYTES) + } + else if (_RXmode == ATB_RX_MODE_READ_BYTES) { - if (_rxReadBytesPtr == NULL || _cbDone == NULL) + if (_rxReadBytesPtr == NULL || _cbDone == NULL) { return 0; } size_t newReadCount = 0; - if (BufferAvailable) + if (BufferAvailable) { r = _RXbuffer->read((char *) _rxReadBytesPtr, _rxSize); _rxSize -= r; _rxReadBytesPtr += r; } - if (_RXbuffer->empty() && (len > 0) && buf) + if (_RXbuffer->empty() && (len > 0) && buf) { r = len; - - if (r > _rxSize) + + if (r > _rxSize) { r = _rxSize; } - + memcpy(_rxReadBytesPtr, buf, r); _rxReadBytesPtr += r; _rxSize -= r; newReadCount += r; } - if (_rxSize == 0) + if (_rxSize == 0) { _RXmode = ATB_RX_MODE_NONE; _cbDone(true, NULL); @@ -709,61 +708,61 @@ size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t *buf, size_t len) // add left over bytes to Buffer return newReadCount; - } - else if (_RXmode == ATB_RX_MODE_TERMINATOR) + } + else if (_RXmode == ATB_RX_MODE_TERMINATOR) { // TODO implement read terminator non string - } - else if (_RXmode == ATB_RX_MODE_TERMINATOR_STRING) + } + else if (_RXmode == ATB_RX_MODE_TERMINATOR_STRING) { - if (_rxReadStringPtr == NULL || _cbDone == NULL) + if (_rxReadStringPtr == NULL || _cbDone == NULL) { return 0; } // handle Buffer - if (BufferAvailable > 0) + if (BufferAvailable > 0) { - while (!_RXbuffer->empty()) + while (!_RXbuffer->empty()) { char c = _RXbuffer->read(); - - if (c == _rxTerminator || c == 0x00) + + if (c == _rxTerminator || c == 0x00) { _RXmode = ATB_RX_MODE_NONE; _cbDone(true, _rxReadStringPtr); return 0; - } - else + } + else { (*_rxReadStringPtr) += c; } } } - if (_RXbuffer->empty() && (len > 0) && buf) + if (_RXbuffer->empty() && (len > 0) && buf) { size_t newReadCount = 0; - - while (newReadCount < len) + + while (newReadCount < len) { char c = (char) * buf; buf++; newReadCount++; - - if (c == _rxTerminator || c == 0x00) + + if (c == _rxTerminator || c == 0x00) { _RXmode = ATB_RX_MODE_NONE; _cbDone(true, _rxReadStringPtr); return newReadCount; - } - else + } + else { (*_rxReadStringPtr) += c; } } - + return newReadCount; } } diff --git a/src/AsyncTCP_RP2040W_buffer.h b/src/AsyncTCP_RP2040W_buffer.h index 6abeda4..8a9b14b 100644 --- a/src/AsyncTCP_RP2040W_buffer.h +++ b/src/AsyncTCP_RP2040W_buffer.h @@ -1,50 +1,51 @@ /**************************************************************************************************************************** AsyncTCP_RP2040W_buffer.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /** - @file AsyncTCP_RP2040W_buffer.h - @date 22.01.2016 - @author Markus Sattler - - Copyright (c) 2015 Markus Sattler. All rights reserved. - This file is part of the Asynv TCP for ESP. - - 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 - -*/ + * @file AsyncTCP_RP2040W_buffer.h + * @date 22.01.2016 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the Asynv TCP for ESP. + * + * 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 ASYNCTCP_RP2040W_BUFFER_H_ #define ASYNCTCP_RP2040W_BUFFER_H_ @@ -58,7 +59,7 @@ #include "AsyncTCP_RP2040W.h" -typedef enum +typedef enum { ATB_RX_MODE_NONE, ATB_RX_MODE_FREE, @@ -69,7 +70,7 @@ typedef enum ///////////////////////////////////////////////////////// -class AsyncTCPbuffer: public Print +class AsyncTCPbuffer: public Print { public: diff --git a/src/DebugPrintMacros.h b/src/DebugPrintMacros.h index 06baadc..4ade689 100644 --- a/src/DebugPrintMacros.h +++ b/src/DebugPrintMacros.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** DebugPrintMacros.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ #ifndef _DEBUG_PRINT_MACROS_H @@ -37,28 +38,28 @@ ///////////////////////////////////////////////////////// #if defined(DEBUG_ESP_PORT) && !defined(DEBUG_TIME_STAMP_FMT) -#define DEBUG_TIME_STAMP_FMT "%06u.%03u " - -struct _DEBUG_TIME_STAMP -{ - unsigned dec; - unsigned whole; -}; - -inline struct _DEBUG_TIME_STAMP debugTimeStamp() -{ - struct _DEBUG_TIME_STAMP st; - unsigned now = millis() % 1000000000; - st.dec = now % 1000; - st.whole = now / 1000; - return st; -} + #define DEBUG_TIME_STAMP_FMT "%06u.%03u " + + struct _DEBUG_TIME_STAMP + { + unsigned dec; + unsigned whole; + }; + + inline struct _DEBUG_TIME_STAMP debugTimeStamp() + { + struct _DEBUG_TIME_STAMP st; + unsigned now = millis() % 1000000000; + st.dec = now % 1000; + st.whole = now / 1000; + return st; + } #endif ///////////////////////////////////////////////////////// #if defined(DEBUG_ESP_PORT) && !defined(DEBUG_GENERIC) -#define DEBUG_GENERIC( module, format, ... ) \ + #define DEBUG_GENERIC( module, format, ... ) \ do { \ struct _DEBUG_TIME_STAMP st = debugTimeStamp(); \ DEBUG_ESP_PORT.printf( DEBUG_TIME_STAMP_FMT module " " format, st.whole, st.dec, ##__VA_ARGS__ ); \ @@ -68,7 +69,7 @@ inline struct _DEBUG_TIME_STAMP debugTimeStamp() ///////////////////////////////////////////////////////// #if defined(DEBUG_ESP_PORT) && !defined(DEBUG_GENERIC_P) -#define DEBUG_GENERIC_P( module, format, ... ) \ + #define DEBUG_GENERIC_P( module, format, ... ) \ do { \ struct _DEBUG_TIME_STAMP st = debugTimeStamp(); \ DEBUG_ESP_PORT.printf_P(PSTR( DEBUG_TIME_STAMP_FMT module " " format ), st.whole, st.dec, ##__VA_ARGS__ ); \ @@ -78,7 +79,7 @@ inline struct _DEBUG_TIME_STAMP debugTimeStamp() ///////////////////////////////////////////////////////// #if defined(DEBUG_GENERIC) && !defined(ASSERT_GENERIC) -#define ASSERT_GENERIC( a, module ) \ + #define ASSERT_GENERIC( a, module ) \ do { \ if ( !(a) ) { \ DEBUG_GENERIC( module, "%s:%s:%u: ASSERT("#a") failed!\n", __FILE__, __func__, __LINE__); \ @@ -90,7 +91,7 @@ inline struct _DEBUG_TIME_STAMP debugTimeStamp() ///////////////////////////////////////////////////////// #if defined(DEBUG_GENERIC_P) && !defined(ASSERT_GENERIC_P) -#define ASSERT_GENERIC_P( a, module ) \ + #define ASSERT_GENERIC_P( a, module ) \ do { \ if ( !(a) ) { \ DEBUG_GENERIC_P( module, "%s:%s:%u: ASSERT("#a") failed!\n", __FILE__, __func__, __LINE__); \ diff --git a/src/SyncClient.cpp b/src/SyncClient.cpp index 7561084..d09f960 100644 --- a/src/SyncClient.cpp +++ b/src/SyncClient.cpp @@ -1,26 +1,27 @@ /**************************************************************************************************************************** SyncClient.cpp - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -103,7 +104,7 @@ SyncClient::SyncClient(AsyncClient *client, size_t txBufLen) ///////////////////////////////////////////////////////// -SyncClient::~SyncClient() +SyncClient::~SyncClient() { if (0 == unref()) _release(); @@ -111,9 +112,9 @@ SyncClient::~SyncClient() ///////////////////////////////////////////////////////// -void SyncClient::_release() +void SyncClient::_release() { - if (_client != NULL) + if (_client != NULL) { _client->onData(NULL, NULL); _client->onAck(NULL, NULL); @@ -121,15 +122,15 @@ void SyncClient::_release() _client->abort(); _client = NULL; } - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; delete b; } - - while (_rx_buffer != NULL) + + while (_rx_buffer != NULL) { cbuf *b = _rx_buffer; _rx_buffer = _rx_buffer->next; @@ -139,69 +140,68 @@ void SyncClient::_release() ///////////////////////////////////////////////////////// -int SyncClient::ref() +int SyncClient::ref() { - if (_ref == NULL) + if (_ref == NULL) { _ref = new (std::nothrow) int; - + if (_ref != NULL) *_ref = 0; else return -1; } - + return (++*_ref); } ///////////////////////////////////////////////////////// -int SyncClient::unref() +int SyncClient::unref() { int count = -1; - - if (_ref != NULL) + + if (_ref != NULL) { count = --*_ref; - - if (0 == count) + + if (0 == count) { delete _ref; _ref = NULL; } } - + return count; } ///////////////////////////////////////////////////////// #if ASYNC_TCP_SSL_ENABLED - int SyncClient::_connect(const IPAddress& ip, uint16_t port, bool secure) +int SyncClient::_connect(const IPAddress& ip, uint16_t port, bool secure) #else - int SyncClient::_connect(const IPAddress& ip, uint16_t port) +int SyncClient::_connect(const IPAddress& ip, uint16_t port) #endif { if (connected()) return 0; - + if (_client != NULL) delete _client; _client = new (std::nothrow) AsyncClient(); - + if (_client == NULL) return 0; - _client->onConnect([](void *obj, AsyncClient * c) + _client->onConnect([](void *obj, AsyncClient * c) { ((SyncClient*)(obj))->_onConnect(c); }, this); - + _attachCallbacks_Disconnect(); - + #if ASYNC_TCP_SSL_ENABLED - if (_client->connect(ip, port, secure)) #else if (_client->connect(ip, port)) @@ -209,41 +209,40 @@ int SyncClient::unref() { while (_client != NULL && !_client->connected() && !_client->disconnecting()) delay(1); - + return connected(); } - + return 0; } ///////////////////////////////////////////////////////// #if ASYNC_TCP_SSL_ENABLED - int SyncClient::connect(const char *host, uint16_t port, bool secure) +int SyncClient::connect(const char *host, uint16_t port, bool secure) #else - int SyncClient::connect(const char *host, uint16_t port) +int SyncClient::connect(const char *host, uint16_t port) #endif { if (connected()) return 0; - + if (_client != NULL) delete _client; _client = new (std::nothrow) AsyncClient(); - + if (_client == NULL) return 0; - _client->onConnect([](void *obj, AsyncClient * c) + _client->onConnect([](void *obj, AsyncClient * c) { ((SyncClient*)(obj))->_onConnect(c); }, this); - + _attachCallbacks_Disconnect(); - + #if ASYNC_TCP_SSL_ENABLED - if (_client->connect(host, port, secure)) #else if (_client->connect(host, port)) @@ -251,10 +250,10 @@ int SyncClient::unref() { while (_client != NULL && !_client->connected() && !_client->disconnecting()) delay(1); - + return connected(); } - + return 0; } @@ -273,18 +272,18 @@ int SyncClient::unref() Note, this is optional, the old behavior is the default. */ -SyncClient & SyncClient::operator=(const SyncClient &other) +SyncClient & SyncClient::operator=(const SyncClient &other) { int *rhsref = other._ref; ++*rhsref; // Just in case the left and right side are the same object with different containers - + if (0 == unref()) _release(); - + _ref = other._ref; ref(); --*rhsref; - + // Why do I not test _tx_buffer for != NULL and free? // I allow for the lh target container, to be a copy of an active // connection. Thus we are just reusing the container. @@ -292,15 +291,15 @@ SyncClient & SyncClient::operator=(const SyncClient &other) _tx_buffer_size = other._tx_buffer_size; _tx_buffer = other._tx_buffer; _client = other._client; - + if (_client != NULL && _tx_buffer == NULL) _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); _rx_buffer = other._rx_buffer; - + if (_client) _attachCallbacks(); - + return *this; } @@ -309,36 +308,35 @@ SyncClient & SyncClient::operator=(const SyncClient &other) #else // ! SYNCCLIENT_NEW_OPERATOR_EQUAL // This is the origianl logic with null checks -SyncClient & SyncClient::operator=(const SyncClient &other) +SyncClient & SyncClient::operator=(const SyncClient &other) { - if (_client != NULL) + if (_client != NULL) { _client->abort(); _client->free(); _client = NULL; } - _tx_buffer_size = other._tx_buffer_size; - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; delete b; } - - while (_rx_buffer != NULL) + + while (_rx_buffer != NULL) { cbuf *b = _rx_buffer; _rx_buffer = b->next; delete b; } - + if (other._client != NULL) _tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size); _client = other._client; - + if (_client) _attachCallbacks(); @@ -348,7 +346,7 @@ SyncClient & SyncClient::operator=(const SyncClient &other) ///////////////////////////////////////////////////////// -void SyncClient::setTimeout(uint32_t seconds) +void SyncClient::setTimeout(uint32_t seconds) { if (_client != NULL) _client->setRxTimeout(seconds); @@ -356,86 +354,84 @@ void SyncClient::setTimeout(uint32_t seconds) ///////////////////////////////////////////////////////// -uint8_t SyncClient::status() +uint8_t SyncClient::status() { if (_client == NULL) return 0; - + return _client->state(); } ///////////////////////////////////////////////////////// -uint8_t SyncClient::connected() +uint8_t SyncClient::connected() { return (_client != NULL && _client->connected()); } ///////////////////////////////////////////////////////// -bool SyncClient::stop(unsigned int maxWaitMs) +bool SyncClient::stop(unsigned int maxWaitMs) { ASYNCTCP_RP2040W_UNUSED(maxWaitMs); - + if (_client != NULL) _client->close(true); - + return true; } ///////////////////////////////////////////////////////// -size_t SyncClient::_sendBuffer() +size_t SyncClient::_sendBuffer() { if (_client == NULL || _tx_buffer == NULL) return 0; - + size_t available = _tx_buffer->available(); - + if ( !connected() || !_client->canSend() || (available == 0) ) return 0; - + size_t sendable = _client->space(); - + if (sendable < available) available = sendable; - + char *out = new (std::nothrow) char[available]; - + if (out == NULL) return 0; _tx_buffer->read(out, available); size_t sent = _client->write(out, available); delete[] out; - + return sent; } ///////////////////////////////////////////////////////// -void SyncClient::_onData(void *data, size_t len) +void SyncClient::_onData(void *data, size_t len) { _client->ackLater(); cbuf *b = new (std::nothrow) cbuf(len + 1); - - if (b != NULL) + + if (b != NULL) { b->write((const char *)data, len); - + if (_rx_buffer == NULL) _rx_buffer = b; - else + else { cbuf *p = _rx_buffer; - while (p->next != NULL) p = p->next; - p->next = b; } - } - else + } + else { // We ran out of memory. This fail causes lost receive data. // The connection should be closed in a manner that conveys something @@ -448,14 +444,14 @@ void SyncClient::_onData(void *data, size_t len) ///////////////////////////////////////////////////////// -void SyncClient::_onDisconnect() +void SyncClient::_onDisconnect() { - if (_client != NULL) + if (_client != NULL) { _client = NULL; } - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; @@ -465,24 +461,24 @@ void SyncClient::_onDisconnect() ///////////////////////////////////////////////////////// -void SyncClient::_onConnect(AsyncClient *c) +void SyncClient::_onConnect(AsyncClient *c) { _client = c; - - if (_tx_buffer != NULL) + + if (_tx_buffer != NULL) { cbuf *b = _tx_buffer; _tx_buffer = NULL; delete b; } - + _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); _attachCallbacks_AfterConnected(); } ///////////////////////////////////////////////////////// -void SyncClient::_attachCallbacks() +void SyncClient::_attachCallbacks() { _attachCallbacks_Disconnect(); _attachCallbacks_AfterConnected(); @@ -490,7 +486,7 @@ void SyncClient::_attachCallbacks() ///////////////////////////////////////////////////////// -void SyncClient::_attachCallbacks_AfterConnected() +void SyncClient::_attachCallbacks_AfterConnected() { _client->onAck([](void *obj, AsyncClient * c, size_t len, uint32_t time) { @@ -501,8 +497,7 @@ void SyncClient::_attachCallbacks_AfterConnected() }, this); _client->onData([](void *obj, AsyncClient * c, void *data, size_t len) - { - ASYNCTCP_RP2040W_UNUSED(c); + { ASYNCTCP_RP2040W_UNUSED(c); ((SyncClient*)(obj))->_onData(data, len); }, this); @@ -518,7 +513,7 @@ void SyncClient::_attachCallbacks_AfterConnected() void SyncClient::_attachCallbacks_Disconnect() { - _client->onDisconnect([](void *obj, AsyncClient * c) + _client->onDisconnect([](void *obj, AsyncClient * c) { ((SyncClient*)(obj))->_onDisconnect(); delete c; @@ -527,139 +522,139 @@ void SyncClient::_attachCallbacks_Disconnect() ///////////////////////////////////////////////////////// -size_t SyncClient::write(uint8_t data) +size_t SyncClient::write(uint8_t data) { return write(&data, 1); } ///////////////////////////////////////////////////////// -size_t SyncClient::write(const uint8_t *data, size_t len) +size_t SyncClient::write(const uint8_t *data, size_t len) { - if (_tx_buffer == NULL || !connected()) + if (_tx_buffer == NULL || !connected()) { return 0; } - + size_t toWrite = 0; size_t toSend = len; - - while (_tx_buffer->room() < toSend) + + while (_tx_buffer->room() < toSend) { toWrite = _tx_buffer->room(); _tx_buffer->write((const char*)data, toWrite); - + while (connected() && !_client->canSend()) delay(0); - + if (!connected()) return 0; - + _sendBuffer(); toSend -= toWrite; } - + _tx_buffer->write((const char*)(data + (len - toSend)), toSend); - + if (connected() && _client->canSend()) _sendBuffer(); - + return len; } ///////////////////////////////////////////////////////// -int SyncClient::available() +int SyncClient::available() { - if (_rx_buffer == NULL) + if (_rx_buffer == NULL) return 0; - - size_t a = 0; + + size_t a = 0; cbuf *b = _rx_buffer; - - while (b != NULL) + + while (b != NULL) { a += b->available(); b = b->next; } - + return a; } ///////////////////////////////////////////////////////// -int SyncClient::peek() +int SyncClient::peek() { - if (_rx_buffer == NULL) + if (_rx_buffer == NULL) return -1; - + return _rx_buffer->peek(); } ///////////////////////////////////////////////////////// -int SyncClient::read(uint8_t *data, size_t len) +int SyncClient::read(uint8_t *data, size_t len) { - if (_rx_buffer == NULL) + if (_rx_buffer == NULL) return -1; size_t readSoFar = 0; - - while (_rx_buffer != NULL && (len - readSoFar) >= _rx_buffer->available()) + + while (_rx_buffer != NULL && (len - readSoFar) >= _rx_buffer->available()) { cbuf *b = _rx_buffer; _rx_buffer = _rx_buffer->next; size_t toRead = b->available(); readSoFar += b->read((char*)(data + readSoFar), toRead); - - if (connected()) + + if (connected()) { _client->ack(b->size() - 1); } - + delete b; } - - if (_rx_buffer != NULL && readSoFar < len) + + if (_rx_buffer != NULL && readSoFar < len) { readSoFar += _rx_buffer->read((char*)(data + readSoFar), (len - readSoFar)); } - + return readSoFar; } ///////////////////////////////////////////////////////// -int SyncClient::read() +int SyncClient::read() { uint8_t res = 0; - + if (read(&res, 1) != 1) return -1; - + return res; } ///////////////////////////////////////////////////////// -bool SyncClient::flush(unsigned int maxWaitMs) +bool SyncClient::flush(unsigned int maxWaitMs) { ASYNCTCP_RP2040W_UNUSED(maxWaitMs); - + if (_tx_buffer == NULL || !connected()) return false; - - if (_tx_buffer->available()) + + if (_tx_buffer->available()) { while (connected() && !_client->canSend()) delay(0); - + if (_client == NULL || _tx_buffer == NULL) return false; - + _sendBuffer(); } - + return true; } diff --git a/src/SyncClient.h b/src/SyncClient.h index 6a4c9b2..a6b2761 100644 --- a/src/SyncClient.h +++ b/src/SyncClient.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** SyncClient.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -63,7 +64,7 @@ class AsyncClient; ///////////////////////////////////////////////////////// -class SyncClient: public Client +class SyncClient: public Client { private: AsyncClient *_client; @@ -88,56 +89,56 @@ class SyncClient: public Client int ref(); int unref(); - - operator bool() + + operator bool() { return connected(); } - + SyncClient & operator=(const SyncClient &other); #if ASYNC_TCP_SSL_ENABLED int _connect(const IPAddress& ip, uint16_t port, bool secure); - - int connect(CONST IPAddress& ip, uint16_t port, bool secure) + + int connect(CONST IPAddress& ip, uint16_t port, bool secure) { return _connect(ip, port, secure); } - - int connect(IPAddress ip, uint16_t port, bool secure) + + int connect(IPAddress ip, uint16_t port, bool secure) { return _connect(reinterpret_cast(ip), port, secure); } - + int connect(const char *host, uint16_t port, bool secure); - - int connect(CONST IPAddress& ip, uint16_t port) + + int connect(CONST IPAddress& ip, uint16_t port) { return _connect(ip, port, false); } - - int connect(IPAddress ip, uint16_t port) + + int connect(IPAddress ip, uint16_t port) { return _connect(reinterpret_cast(ip), port, false); } - - int connect(const char *host, uint16_t port) + + int connect(const char *host, uint16_t port) { return connect(host, port, false); } #else int _connect(const IPAddress& ip, uint16_t port); - - int connect(CONST IPAddress& ip, uint16_t port) + + int connect(CONST IPAddress& ip, uint16_t port) { return _connect(ip, port); } - - int connect(IPAddress ip, uint16_t port) + + int connect(IPAddress ip, uint16_t port) { return _connect(reinterpret_cast(ip), port); } - + int connect(const char *host, uint16_t port); #endif void setTimeout(uint32_t seconds); @@ -147,17 +148,17 @@ class SyncClient: public Client bool stop(unsigned int maxWaitMs); bool flush(unsigned int maxWaitMs); - - void stop() + + void stop() { (void)stop(0); } - - void flush() + + void flush() { (void)flush(0); } - + size_t write(uint8_t data); size_t write(const uint8_t *data, size_t len); diff --git a/src/async_config.h b/src/async_config.h index dbfcff4..384f844 100644 --- a/src/async_config.h +++ b/src/async_config.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** async_config.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ #ifndef _RP2040W_ASYNC_CONFIG_H_ diff --git a/src/c_types.h b/src/c_types.h index 2d62360..b72bfa2 100644 --- a/src/c_types.h +++ b/src/c_types.h @@ -1,26 +1,26 @@ /* - ESPRESSIF MIT License - - Copyright (c) 2016 - - Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - it is free of charge, to any person obtaining a copy of this software and associated - documentation files (the "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the Software is furnished - to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ #ifndef _C_TYPES_H_ #define _C_TYPES_H_ @@ -68,7 +68,7 @@ typedef double real64; #endif /* NULL */ /* probably should not put STATUS here */ -typedef enum +typedef enum { OK = 0, FAIL, diff --git a/src/cbuf.cpp b/src/cbuf.cpp index aac1ecc..51335f7 100644 --- a/src/cbuf.cpp +++ b/src/cbuf.cpp @@ -1,48 +1,48 @@ -/* - 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 -*/ +/* + 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 "cbuf.h" #include "c_types.h" cbuf::cbuf(size_t size) : - next(NULL), _size(size), _buf(new char[size]), _bufend(_buf + size), _begin(_buf), _end(_begin) + next(NULL), _size(size), _buf(new char[size]), _bufend(_buf + size), _begin(_buf), _end(_begin) { } -cbuf::~cbuf() +cbuf::~cbuf() { delete[] _buf; } -size_t cbuf::resizeAdd(size_t addSize) +size_t cbuf::resizeAdd(size_t addSize) { return resize(_size + addSize); } -size_t cbuf::resize(size_t newSize) +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)) + if ((newSize <= bytes_available) || (newSize == _size)) { return _size; } @@ -50,12 +50,12 @@ size_t cbuf::resize(size_t newSize) char *newbuf = new char[newSize]; char *oldbuf = _buf; - if (!newbuf) + if (!newbuf) { return _size; } - if (_buf) + if (_buf) { read(newbuf, bytes_available); memset((newbuf + bytes_available), 0x00, (newSize - bytes_available)); @@ -72,32 +72,32 @@ size_t cbuf::resize(size_t newSize) return _size; } -size_t ICACHE_RAM_ATTR cbuf::available() const +size_t ICACHE_RAM_ATTR cbuf::available() const { - if (_end >= _begin) + if (_end >= _begin) { return _end - _begin; } - + return _size - (_begin - _end); } -size_t cbuf::size() +size_t cbuf::size() { return _size; } -size_t cbuf::room() const +size_t cbuf::room() const { - if (_end >= _begin) + if (_end >= _begin) { return _size - (_end - _begin) - 1; } - + return _begin - _end - 1; } -int cbuf::peek() +int cbuf::peek() { if (empty()) return -1; @@ -105,14 +105,14 @@ int cbuf::peek() return static_cast(*_begin); } -size_t cbuf::peek(char *dst, size_t size) +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)) + + if (_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { size_t top_size = _bufend - _begin; memcpy(dst, _begin, top_size); @@ -120,30 +120,30 @@ size_t cbuf::peek(char *dst, size_t size) size_to_read -= top_size; dst += top_size; } - + memcpy(dst, begin, size_to_read); - + return size_read; } -int ICACHE_RAM_ATTR cbuf::read() +int ICACHE_RAM_ATTR cbuf::read() { if (empty()) return -1; char result = *_begin; _begin = wrap_if_bufend(_begin + 1); - + return static_cast(result); } -size_t cbuf::read(char* dst, size_t size) +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)) + + if (_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { size_t top_size = _bufend - _begin; memcpy(dst, _begin, top_size); @@ -151,31 +151,31 @@ size_t cbuf::read(char* dst, size_t size) 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 ICACHE_RAM_ATTR cbuf::write(char c) +size_t ICACHE_RAM_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 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)) + + if (_end >= _begin && size_to_write > (size_t) (_bufend - _end)) { size_t top_size = _bufend - _end; memcpy(_end, src, top_size); @@ -183,39 +183,39 @@ size_t cbuf::write(const char* src, size_t size) 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() +void cbuf::flush() { _begin = _buf; _end = _buf; } -size_t cbuf::remove(size_t size) +size_t cbuf::remove(size_t size) { size_t bytes_available = available(); - - if (size >= bytes_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)) + + 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(); } diff --git a/src/cbuf.h b/src/cbuf.h index b16653a..b61d8b9 100644 --- a/src/cbuf.h +++ b/src/cbuf.h @@ -1,22 +1,22 @@ -/* - 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 -*/ +/* + 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 @@ -25,7 +25,7 @@ #include #include -class cbuf +class cbuf { public: cbuf(size_t size); @@ -38,12 +38,12 @@ class cbuf size_t room() const; - inline bool empty() const + inline bool empty() const { return _begin == _end; } - inline bool full() const + inline bool full() const { return wrap_if_bufend(_end + 1) == _begin; } @@ -63,7 +63,7 @@ class cbuf cbuf *next; private: - inline char* wrap_if_bufend(char* ptr) const + inline char* wrap_if_bufend(char* ptr) const { return (ptr == _bufend) ? _buf : ptr; } diff --git a/src/tcp_axtls.c b/src/tcp_axtls.c index b57b6cc..9dcdee0 100644 --- a/src/tcp_axtls.c +++ b/src/tcp_axtls.c @@ -1,26 +1,27 @@ /**************************************************************************************************************************** tcp_axtls.c - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -43,9 +44,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* - Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP) - Original Code and Inspiration: Slavey Karadzhov -*/ + * Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP) + * Original Code and Inspiration: Slavey Karadzhov + */ #if !defined(_ASYNCTCP_RP2040W_LOGLEVEL_) #define _ASYNCTCP_RP2040W_LOGLEVEL_ 1 @@ -74,53 +75,53 @@ static uint8_t _tcp_ssl_has_client = 0; ///////////////////////////////////////////////////////// -SSL_CTX * tcp_ssl_new_server_ctx(const char *cert, const char *private_key_file, const char *password) +SSL_CTX * tcp_ssl_new_server_ctx(const char *cert, const char *private_key_file, const char *password) { uint32_t options = SSL_CONNECT_IN_PARTS; SSL_CTX *ssl_ctx; - if (private_key_file) + if (private_key_file) { options |= SSL_NO_DEFAULT_KEY; } - if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL) + if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL) { TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: failed to allocate context\n"); return NULL; } - if (private_key_file) + if (private_key_file) { int obj_type = SSL_OBJ_RSA_KEY; - + if (strstr(private_key_file, ".p8")) obj_type = SSL_OBJ_PKCS8; else if (strstr(private_key_file, ".p12")) obj_type = SSL_OBJ_PKCS12; - if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password)) + if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password)) { TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: load private key '%s' failed\n", private_key_file); return NULL; } } - if (cert) + if (cert) { - if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert, NULL)) + if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert, NULL)) { TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: load certificate '%s' failed\n", cert); return NULL; } } - + return ssl_ctx; } ///////////////////////////////////////////////////////// -struct tcp_ssl_pcb +struct tcp_ssl_pcb { struct tcp_pcb *tcp; int fd; @@ -145,27 +146,27 @@ static int tcp_ssl_next_fd = 0; ///////////////////////////////////////////////////////// -uint8_t tcp_ssl_has_client() +uint8_t tcp_ssl_has_client() { return _tcp_ssl_has_client; } ///////////////////////////////////////////////////////// -tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) +tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { - if (tcp_ssl_next_fd < 0) + if (tcp_ssl_next_fd < 0) { tcp_ssl_next_fd = 0;//overflow } tcp_ssl_t * new_item = (tcp_ssl_t*)malloc(sizeof(tcp_ssl_t)); - - if (!new_item) + + if (!new_item) { TCP_SSL_DEBUG("tcp_ssl_new: failed to allocate tcp_ssl\n"); - + return NULL; } @@ -183,89 +184,89 @@ tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) new_item->type = TCP_SSL_TYPE_CLIENT; new_item->fd = tcp_ssl_next_fd++; - if (tcp_ssl_array == NULL) + if (tcp_ssl_array == NULL) { tcp_ssl_array = new_item; - } - else + } + else { tcp_ssl_t * item = tcp_ssl_array; - + while (item->next != NULL) item = item->next; - + item->next = new_item; } TCP_SSL_DEBUG("tcp_ssl_new: %d\n", new_item->fd); - + return new_item; } ///////////////////////////////////////////////////////// -tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) +tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { - if (tcp == NULL) + if (tcp == NULL) { return NULL; } - + tcp_ssl_t * item = tcp_ssl_array; - - while (item && item->tcp != tcp) + + while (item && item->tcp != tcp) { item = item->next; } - + return item; } ///////////////////////////////////////////////////////// -int tcp_ssl_new_client(struct tcp_pcb *tcp) +int tcp_ssl_new_client(struct tcp_pcb *tcp) { SSL_CTX* ssl_ctx; tcp_ssl_t * tcp_ssl; - if (tcp == NULL) + if (tcp == NULL) { return -1; } - if (tcp_ssl_get(tcp) != NULL) + if (tcp_ssl_get(tcp) != NULL) { TCP_SSL_DEBUG("tcp_ssl_new_client: tcp_ssl already exists\n"); return -1; } ssl_ctx = ssl_ctx_new(SSL_CONNECT_IN_PARTS | SSL_SERVER_VERIFY_LATER, 1); - - if (ssl_ctx == NULL) + + if (ssl_ctx == NULL) { TCP_SSL_DEBUG("tcp_ssl_new_client: failed to allocate ssl context\n"); - + return -1; } tcp_ssl = tcp_ssl_new(tcp); - - if (tcp_ssl == NULL) + + if (tcp_ssl == NULL) { ssl_ctx_free(ssl_ctx); - + return -1; } tcp_ssl->ssl_ctx = ssl_ctx; tcp_ssl->ssl = ssl_client_new(ssl_ctx, tcp_ssl->fd, NULL, 0, NULL); - - if (tcp_ssl->ssl == NULL) + + if (tcp_ssl->ssl == NULL) { TCP_SSL_DEBUG("tcp_ssl_new_client: failed to allocate ssl\n"); tcp_ssl_free(tcp); - + return -1; } @@ -274,30 +275,30 @@ int tcp_ssl_new_client(struct tcp_pcb *tcp) ///////////////////////////////////////////////////////// -int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx) +int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx) { tcp_ssl_t * tcp_ssl; - if (tcp == NULL) + if (tcp == NULL) { return -1; } - if (ssl_ctx == NULL) + if (ssl_ctx == NULL) { return -1; } - if (tcp_ssl_get(tcp) != NULL) + if (tcp_ssl_get(tcp) != NULL) { TCP_SSL_DEBUG("tcp_ssl_new_server: tcp_ssl already exists\n"); - + return -1; } tcp_ssl = tcp_ssl_new(tcp); - - if (tcp_ssl == NULL) + + if (tcp_ssl == NULL) { return -1; } @@ -307,12 +308,12 @@ int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx) _tcp_ssl_has_client = 1; tcp_ssl->ssl = ssl_server_new(ssl_ctx, tcp_ssl->fd); - - if (tcp_ssl->ssl == NULL) + + if (tcp_ssl->ssl == NULL) { TCP_SSL_DEBUG("tcp_ssl_new_server: failed to allocate ssl\n"); tcp_ssl_free(tcp); - + return -1; } @@ -321,69 +322,69 @@ int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx) ///////////////////////////////////////////////////////// -int tcp_ssl_free(struct tcp_pcb *tcp) +int tcp_ssl_free(struct tcp_pcb *tcp) { - if (tcp == NULL) + if (tcp == NULL) { return -1; } tcp_ssl_t * item = tcp_ssl_array; - if (item->tcp == tcp) + if (item->tcp == tcp) { tcp_ssl_array = tcp_ssl_array->next; - - if (item->tcp_pbuf != NULL) + + if (item->tcp_pbuf != NULL) { pbuf_free(item->tcp_pbuf); } - + TCP_SSL_DEBUG("tcp_ssl_free: %d\n", item->fd); - + if (item->ssl) ssl_free(item->ssl); - + if (item->type == TCP_SSL_TYPE_CLIENT && item->ssl_ctx) ssl_ctx_free(item->ssl_ctx); - + if (item->type == TCP_SSL_TYPE_SERVER) _tcp_ssl_has_client = 0; - + free(item); - + return 0; } while (item->next && item->next->tcp != tcp) item = item->next; - if (item->next == NULL) + if (item->next == NULL) { return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found } tcp_ssl_t * i = item->next; item->next = i->next; - - if (i->tcp_pbuf != NULL) + + if (i->tcp_pbuf != NULL) { pbuf_free(i->tcp_pbuf); } - + TCP_SSL_DEBUG("tcp_ssl_free: %d\n", i->fd); - + if (i->ssl) ssl_free(i->ssl); - + if (i->type == TCP_SSL_TYPE_CLIENT && i->ssl_ctx) ssl_ctx_free(i->ssl_ctx); - + if (i->type == TCP_SSL_TYPE_SERVER) _tcp_ssl_has_client = 0; - + free(i); - + return 0; } @@ -391,41 +392,40 @@ int tcp_ssl_free(struct tcp_pcb *tcp) #ifdef AXTLS_2_0_0_SNDBUF -int tcp_ssl_sndbuf(struct tcp_pcb *tcp) +int tcp_ssl_sndbuf(struct tcp_pcb *tcp) { int expected; int available; int result = -1; - if (tcp == NULL) + if (tcp == NULL) { return result; } - tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - - if (!tcp_ssl) + + if (!tcp_ssl) { TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_ssl is NULL\n"); return result; } - + available = tcp_sndbuf(tcp); - - if (!available) + + if (!available) { TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_sndbuf is zero\n"); return 0; } - + result = available; - - while ((expected = ssl_calculate_write_length(tcp_ssl->ssl, result)) > available) + + while ((expected = ssl_calculate_write_length(tcp_ssl->ssl, result)) > available) { result -= (expected - available) + 4; } - if (expected > 0) + if (expected > 0) { //TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_sndbuf is %d from %d\n", result, available); return result; @@ -438,48 +438,47 @@ int tcp_ssl_sndbuf(struct tcp_pcb *tcp) ///////////////////////////////////////////////////////// -int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) +int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { - if (tcp == NULL) + if (tcp == NULL) { return -1; } - + tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - - if (!tcp_ssl) + + if (!tcp_ssl) { TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n"); - + return 0; } - + tcp_ssl->last_wr = 0; #ifdef AXTLS_2_0_0_SNDBUF int expected_len = ssl_calculate_write_length(tcp_ssl->ssl, len); int available_len = tcp_sndbuf(tcp); - - if (expected_len < 0 || expected_len > available_len) + + if (expected_len < 0 || expected_len > available_len) { TCP_SSL_DEBUG("tcp_ssl_write: data will not fit! %u < %d(%u)\r\n", available_len, expected_len, len); - + return -1; } - #endif // AXTLS_2_0_0_SNDBUF int rc = ssl_write(tcp_ssl->ssl, data, len); //TCP_SSL_DEBUG("tcp_ssl_write: %u -> %d (%d)\r\n", len, tcp_ssl->last_wr, rc); - if (rc < 0) + if (rc < 0) { - if (rc != SSL_CLOSE_NOTIFY) + if (rc != SSL_CLOSE_NOTIFY) { TCP_SSL_DEBUG("tcp_ssl_write error: %d\r\n", rc); } - + return rc; } @@ -498,13 +497,13 @@ int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) < 0 - when there is an error > 0 - the length of the clear text characters that were read */ -int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) +int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { - if (tcp == NULL) + if (tcp == NULL) { return -1; } - + tcp_ssl_t* fd_data = NULL; int read_bytes = 0; @@ -512,14 +511,14 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) uint8_t *read_buf; fd_data = tcp_ssl_get(tcp); - - if (fd_data == NULL) + + if (fd_data == NULL) { TCP_SSL_DEBUG("tcp_ssl_read: tcp_ssl is NULL\n"); return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; } - if (p == NULL) + if (p == NULL) { TCP_SSL_DEBUG("tcp_ssl_read:p == NULL\n"); return ERR_TCP_SSL_INVALID_DATA; @@ -530,49 +529,49 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) fd_data->tcp_pbuf = p; fd_data->pbuf_offset = 0; - do + do { read_bytes = ssl_read(fd_data->ssl, &read_buf); //TCP_SSL_DEBUG("tcp_ssl_ssl_read: %d\n", read_bytes); - - if (read_bytes < SSL_OK) + + if (read_bytes < SSL_OK) { - if (read_bytes != SSL_CLOSE_NOTIFY) + if (read_bytes != SSL_CLOSE_NOTIFY) { TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); } - + total_bytes = read_bytes; break; - } - else if (read_bytes > 0) + } + else if (read_bytes > 0) { - if (fd_data->on_data) + if (fd_data->on_data) { fd_data->on_data(fd_data->arg, tcp, read_buf, read_bytes); } - + total_bytes += read_bytes; - } - else + } + else { - if (fd_data->handshake != SSL_OK) + if (fd_data->handshake != SSL_OK) { fd_data->handshake = ssl_handshake_status(fd_data->ssl); - - if (fd_data->handshake == SSL_OK) + + if (fd_data->handshake == SSL_OK) { //TCP_SSL_DEBUG("tcp_ssl_read: handshake OK\n"); if (fd_data->on_handshake) fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data->ssl); - } - else if (fd_data->handshake != SSL_NOT_OK) + } + else if (fd_data->handshake != SSL_NOT_OK) { TCP_SSL_DEBUG("tcp_ssl_read: handshake error: %d\n", fd_data->handshake); - + if (fd_data->on_error) fd_data->on_error(fd_data->arg, fd_data->tcp, fd_data->handshake); - + return fd_data->handshake; } } @@ -588,46 +587,46 @@ int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) ///////////////////////////////////////////////////////// -SSL * tcp_ssl_get_ssl(struct tcp_pcb *tcp) +SSL * tcp_ssl_get_ssl(struct tcp_pcb *tcp) { tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - - if (tcp_ssl) + + if (tcp_ssl) { return tcp_ssl->ssl; } - + return NULL; } ///////////////////////////////////////////////////////// -bool tcp_ssl_has(struct tcp_pcb *tcp) +bool tcp_ssl_has(struct tcp_pcb *tcp) { return tcp_ssl_get(tcp) != NULL; } ///////////////////////////////////////////////////////// -int tcp_ssl_is_server(struct tcp_pcb *tcp) +int tcp_ssl_is_server(struct tcp_pcb *tcp) { tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - - if (tcp_ssl) + + if (tcp_ssl) { return tcp_ssl->type; } - + return -1; } ///////////////////////////////////////////////////////// -void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg) +void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg) { tcp_ssl_t * item = tcp_ssl_get(tcp); - - if (item) + + if (item) { item->arg = arg; } @@ -635,11 +634,11 @@ void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg) ///////////////////////////////////////////////////////// -void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg) +void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg) { tcp_ssl_t * item = tcp_ssl_get(tcp); - - if (item) + + if (item) { item->on_data = arg; } @@ -647,11 +646,11 @@ void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg) ///////////////////////////////////////////////////////// -void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg) +void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg) { tcp_ssl_t * item = tcp_ssl_get(tcp); - - if (item) + + if (item) { item->on_handshake = arg; } @@ -659,11 +658,11 @@ void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg) ///////////////////////////////////////////////////////// -void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg) +void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg) { tcp_ssl_t * item = tcp_ssl_get(tcp); - - if (item) + + if (item) { item->on_error = arg; } @@ -676,7 +675,7 @@ static void * _tcp_ssl_file_arg = NULL; ///////////////////////////////////////////////////////// -void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg) +void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg) { _tcp_ssl_file_cb = cb; _tcp_ssl_file_arg = arg; @@ -684,30 +683,30 @@ void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg) ///////////////////////////////////////////////////////// -int ax_get_file(const char *filename, uint8_t **buf) +int ax_get_file(const char *filename, uint8_t **buf) { //TCP_SSL_DEBUG("ax_get_file: %s\n", filename); - if (_tcp_ssl_file_cb) + if (_tcp_ssl_file_cb) { return _tcp_ssl_file_cb(_tcp_ssl_file_arg, filename, buf); } - + *buf = 0; - + return 0; } ///////////////////////////////////////////////////////// -tcp_ssl_t* tcp_ssl_get_by_fd(int fd) +tcp_ssl_t* tcp_ssl_get_by_fd(int fd) { tcp_ssl_t * item = tcp_ssl_array; - - while (item && item->fd != fd) + + while (item && item->fd != fd) { item = item->next; } - + return item; } @@ -716,7 +715,7 @@ tcp_ssl_t* tcp_ssl_get_by_fd(int fd) /* The LWIP tcp raw version of the SOCKET_WRITE(A, B, C) */ -int ax_port_write(int fd, uint8_t *data, uint16_t len) +int ax_port_write(int fd, uint8_t *data, uint16_t len) { tcp_ssl_t *fd_data = NULL; int tcp_len = 0; @@ -725,63 +724,63 @@ int ax_port_write(int fd, uint8_t *data, uint16_t len) //TCP_SSL_DEBUG("ax_port_write: %d, %d\n", fd, len); fd_data = tcp_ssl_get_by_fd(fd); - - if (fd_data == NULL) + + if (fd_data == NULL) { //TCP_SSL_DEBUG("ax_port_write: tcp_ssl[%d] is NULL\n", fd); - + return ERR_MEM; } - if (data == NULL || len == 0) + if (data == NULL || len == 0) { return 0; } - if (tcp_sndbuf(fd_data->tcp) < len) + if (tcp_sndbuf(fd_data->tcp) < len) { tcp_len = tcp_sndbuf(fd_data->tcp); - - if (tcp_len == 0) + + if (tcp_len == 0) { TCP_SSL_DEBUG("ax_port_write: tcp_sndbuf is zero: %d\n", len); - + return ERR_MEM; - } - } - else + } + } + else { tcp_len = len; } - if (tcp_len > 2 * fd_data->tcp->mss) + if (tcp_len > 2 * fd_data->tcp->mss) { tcp_len = 2 * fd_data->tcp->mss; } err = tcp_write(fd_data->tcp, data, tcp_len, TCP_WRITE_FLAG_COPY); - - if (err < ERR_OK) + + if (err < ERR_OK) { - if (err == ERR_MEM) + if (err == ERR_MEM) { TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len); return err; } - + TCP_SSL_DEBUG("ax_port_write: tcp_write error: %d\n", err); - + return err; - } - else if (err == ERR_OK) + } + else if (err == ERR_OK) { //TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len); err = tcp_output(fd_data->tcp); - - if (err != ERR_OK) + + if (err != ERR_OK) { TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err); - + return err; } } @@ -796,7 +795,7 @@ int ax_port_write(int fd, uint8_t *data, uint16_t len) /* The LWIP tcp raw version of the SOCKET_READ(A, B, C) */ -int ax_port_read(int fd, uint8_t *data, int len) +int ax_port_read(int fd, uint8_t *data, int len) { tcp_ssl_t *fd_data = NULL; uint8_t *read_buf = NULL; @@ -806,34 +805,34 @@ int ax_port_read(int fd, uint8_t *data, int len) //TCP_SSL_DEBUG("ax_port_read: %d, %d\n", fd, len); fd_data = tcp_ssl_get_by_fd(fd); - - if (fd_data == NULL) + + if (fd_data == NULL) { TCP_SSL_DEBUG("ax_port_read: tcp_ssl[%d] is NULL\n", fd); - + return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; } - if (fd_data->tcp_pbuf == NULL || fd_data->tcp_pbuf->tot_len == 0) + if (fd_data->tcp_pbuf == NULL || fd_data->tcp_pbuf->tot_len == 0) { return 0; } read_buf = (uint8_t*) calloc(fd_data->tcp_pbuf->len + 1, sizeof(uint8_t)); pread_buf = read_buf; - - if (pread_buf != NULL) + + if (pread_buf != NULL) { recv_len = pbuf_copy_partial(fd_data->tcp_pbuf, read_buf, len, fd_data->pbuf_offset); fd_data->pbuf_offset += recv_len; } - if (recv_len != 0) + if (recv_len != 0) { memcpy(data, read_buf, recv_len); } - if (len < recv_len) + if (len < recv_len) { TCP_SSL_DEBUG("ax_port_read: got %d bytes more than expected\n", recv_len - len); } diff --git a/src/tcp_axtls.h b/src/tcp_axtls.h index 14b9f0d..e3b3645 100644 --- a/src/tcp_axtls.h +++ b/src/tcp_axtls.h @@ -1,26 +1,27 @@ /**************************************************************************************************************************** tcp_axtls.h - + For RP2040W with CYW43439 WiFi - + AsyncTCP_RP2040W is a library for the RP2040W with CYW43439 WiFi - + Based on and modified from AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_RP2040W - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. - You should have received a copy of the GNU General Public License along with this program. + You should have received a copy of the GNU General Public License along with this program. If not, see . - - Version: 1.1.0 - + + Version: 1.2.0 + Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 13/08/2022 Initial coding for RP2040W with CYW43439 WiFi 1.1.0 K Hoang 25/09/2022 Fix issue with slow browsers or network. Clean up. Remove hard-code if possible + 1.2.0 K Hoang 02/02/2023 Add Client and Server examples *****************************************************************************************************************************/ /* Asynchronous TCP library for Espressif MCUs @@ -43,9 +44,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* - Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP) - Original Code and Inspiration: Slavey Karadzhov -*/ + * Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP) + * Original Code and Inspiration: Slavey Karadzhov + */ #ifndef LWIPR_COMPAT_H #define LWIPR_COMPAT_H @@ -96,7 +97,7 @@ int tcp_ssl_free(struct tcp_pcb *tcp); int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p); #ifdef AXTLS_2_0_0_SNDBUF -int tcp_ssl_sndbuf(struct tcp_pcb *tcp); + int tcp_ssl_sndbuf(struct tcp_pcb *tcp); #endif int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len);