Port to Raspberry Pi Pico W core

Add support for the onboard WiFi chip on the Raspberry Pi Pico W
(RP2040 based ) board using the arduino-pico Arduino core at
https://github.com/earlephilhower/arduino-pico

The PicoW WiFi stack is a mashup of the ESP8266 and ESP32 cores, so
only minimal changes were required.  Defines a new NETWORK_TYPE for
the PicoW.

ESP8266 examples renames to ESP8266_PICO because they all work unmodified
(except for OTA which is handled differently on the Pico)
This commit is contained in:
Earle F. Philhower, III
2023-01-12 09:53:42 -08:00
committed by Markus
parent 323592f622
commit d9a5c629f0
28 changed files with 61 additions and 25 deletions

View File

@ -26,6 +26,7 @@ a WebSocket Server and Client for Arduino based on RFC6455.
- ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/) - ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/)
- ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32) - ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32)
- ESP31B - ESP31B
- Raspberry Pi Pico W [Arduino for Pico](https://github.com/earlephilhower/arduino-pico)
- Particle with STM32 ARM Cortex M3 - Particle with STM32 ARM Cortex M3
- ATmega328 with Ethernet Shield (ATmega branch) - ATmega328 with Ethernet Shield (ATmega branch)
- ATmega328 with enc28j60 (ATmega branch) - ATmega328 with enc28j60 (ATmega branch)

View File

@ -8,15 +8,16 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#ifdef ESP8266 #if defined(ESP8266)
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <Updater.h> #include <Updater.h>
#endif #elif defined(ESP32)
#ifdef ESP32
#include "WiFi.h" #include "WiFi.h"
#include "ESPmDNS.h" #include "ESPmDNS.h"
#include <Update.h> #include <Update.h>
#else
#error Unsupported device
#endif #endif
#include <WiFiUdp.h> #include <WiFiUdp.h>

View File

@ -482,7 +482,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
switch(header->opCode) { switch(header->opCode) {
case WSop_text: case WSop_text:
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload); DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload);
// no break here! // fallthrough
case WSop_binary: case WSop_binary:
case WSop_continuation: case WSop_continuation:
messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); messageReceived(client, header->opCode, payload, header->payloadLen, header->fin);

View File

@ -84,6 +84,15 @@
#define GET_FREE_HEAP System.freeMemory() #define GET_FREE_HEAP System.freeMemory()
#define WEBSOCKETS_YIELD() #define WEBSOCKETS_YIELD()
#define WEBSOCKETS_YIELD_MORE() #define WEBSOCKETS_YIELD_MORE()
#elif defined(ARDUINO_ARCH_RP2040)
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
#define WEBSOCKETS_USE_BIG_MEM
#define GET_FREE_HEAP rp2040.getFreeHeap()
#define WEBSOCKETS_YIELD() yield()
#define WEBSOCKETS_YIELD_MORE() delay(1)
#else #else
// atmega328p has only 2KB ram! // atmega328p has only 2KB ram!
@ -104,6 +113,7 @@
#define NETWORK_ENC28J60 (3) #define NETWORK_ENC28J60 (3)
#define NETWORK_ESP32 (4) #define NETWORK_ESP32 (4)
#define NETWORK_ESP32_ETH (5) #define NETWORK_ESP32_ETH (5)
#define NETWORK_RP2040 (6)
// max size of the WS Message Header // max size of the WS Message Header
#define WEBSOCKETS_MAX_HEADER_SIZE (14) #define WEBSOCKETS_MAX_HEADER_SIZE (14)
@ -118,6 +128,10 @@
#elif defined(ESP32) #elif defined(ESP32)
#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32 #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32
//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH //#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH
#elif defined(ARDUINO_ARCH_RP2040)
#define WEBSOCKETS_NETWORK_TYPE NETWORK_RP2040
#else #else
#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 #define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100
@ -201,6 +215,15 @@
#define WEBSOCKETS_NETWORK_CLASS WiFiClient #define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer #define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define SSL_BARESSL
#define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
#else #else
#error "no network type selected!" #error "no network type selected!"
#endif #endif

View File

@ -28,23 +28,30 @@
#include <WebSocketsServer.h> #include <WebSocketsServer.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#if ((WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)) && WEBSERVER_HAS_HOOK
class WebSockets4WebServer : public WebSocketsServerCore { class WebSockets4WebServer : public WebSocketsServerCore {
#if defined(ESP8266)
using WebServerClass = ESP8266WebServer;
#else
using WebServerClass = WebServer;
#endif
public: public:
WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino") WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino")
: WebSocketsServerCore(origin, protocol) { : WebSocketsServerCore(origin, protocol) {
begin(); begin();
} }
ESP8266WebServer::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) { WebServerClass::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) {
onEvent(event); onEvent(event);
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) { return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, WebServerClass::ContentTypeFunction contentType) {
(void)contentType; (void)contentType;
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) { if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE; return WebServerClass::CLIENT_REQUEST_CAN_CONTINUE;
} }
// allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients()) // allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
@ -63,7 +70,7 @@ class WebSockets4WebServer : public WebSocketsServerCore {
} }
// tell webserver to not close but forget about this client // tell webserver to not close but forget about this client
return ESP8266WebServer::CLIENT_IS_GIVEN; return WebServerClass::CLIENT_IS_GIVEN;
}; };
} }
}; };

View File

@ -76,6 +76,8 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
#ifdef ESP8266 #ifdef ESP8266
randomSeed(RANDOM_REG32); randomSeed(RANDOM_REG32);
#elif defined(ARDUINO_ARCH_RP2040)
randomSeed(rp2040.hwrand32());
#else #else
// todo find better seed // todo find better seed
randomSeed(millis()); randomSeed(millis());
@ -224,7 +226,7 @@ void WebSocketsClient::loop(void) {
_client.ssl->setCACert(_CA_cert); _client.ssl->setCACert(_CA_cert);
#elif defined(ESP8266) && defined(SSL_AXTLS) #elif defined(ESP8266) && defined(SSL_AXTLS)
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1); _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
#elif defined(ESP8266) && defined(SSL_BARESSL) #elif (defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)) && defined(SSL_BARESSL)
_client.ssl->setTrustAnchors(_CA_cert); _client.ssl->setTrustAnchors(_CA_cert);
#else #else
#error setCACert not implemented #error setCACert not implemented
@ -473,7 +475,7 @@ void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, u
void WebSocketsClient::clientDisconnect(WSclient_t * client) { void WebSocketsClient::clientDisconnect(WSclient_t * client) {
bool event = false; bool event = false;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
if(client->isSSL && client->ssl) { if(client->isSSL && client->ssl) {
if(client->ssl->connected()) { if(client->ssl->connected()) {
client->ssl->flush(); client->ssl->flush();
@ -864,7 +866,7 @@ void WebSocketsClient::connectedCb() {
_client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
#endif #endif
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
_client.tcp->setNoDelay(true); _client.tcp->setNoDelay(true);
#endif #endif

View File

@ -85,6 +85,8 @@ void WebSocketsServerCore::begin(void) {
#elif defined(ESP32) #elif defined(ESP32)
#define DR_REG_RNG_BASE 0x3ff75144 #define DR_REG_RNG_BASE 0x3ff75144
randomSeed(READ_PERI_REG(DR_REG_RNG_BASE)); randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
#elif defined(ARDUINO_ARCH_RP2040)
randomSeed(rp2040.hwrand32());
#else #else
// TODO find better seed // TODO find better seed
randomSeed(millis()); randomSeed(millis());
@ -394,7 +396,7 @@ bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
return clientIsConnected(client); return clientIsConnected(client);
} }
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
/** /**
* get an IP for a client * get an IP for a client
* @param num uint8_t client id * @param num uint8_t client id
@ -439,7 +441,7 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
#endif #endif
client->status = WSC_HEADER; client->status = WSC_HEADER;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
#ifndef NODEBUG_WEBSOCKETS #ifndef NODEBUG_WEBSOCKETS
IPAddress ip = client->tcp->remoteIP(); IPAddress ip = client->tcp->remoteIP();
#endif #endif
@ -521,7 +523,7 @@ void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
} }
if(client->tcp) { if(client->tcp) {
if(client->tcp->connected()) { if(client->tcp->connected()) {
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_RP2040)
client->tcp->flush(); client->tcp->flush();
#endif #endif
client->tcp->stop(); client->tcp->stop();
@ -540,7 +542,7 @@ void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
* @param client WSclient_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
*/ */
void WebSocketsServerCore::clientDisconnect(WSclient_t * client) { void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
if(client->isSSL && client->ssl) { if(client->isSSL && client->ssl) {
if(client->ssl->connected()) { if(client->ssl->connected()) {
client->ssl->flush(); client->ssl->flush();
@ -614,7 +616,7 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
if(!client) { if(!client) {
// no free space to handle client // no free space to handle client
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
#ifndef NODEBUG_WEBSOCKETS #ifndef NODEBUG_WEBSOCKETS
IPAddress ip = tcpClient->remoteIP(); IPAddress ip = tcpClient->remoteIP();
#endif #endif
@ -639,7 +641,7 @@ WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tc
* Handle incoming Connection Request * Handle incoming Connection Request
*/ */
void WebSocketsServer::handleNewClients(void) { void WebSocketsServer::handleNewClients(void) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
while(_server->hasClient()) { while(_server->hasClient()) {
#endif #endif
@ -652,7 +654,7 @@ void WebSocketsServer::handleNewClients(void) {
handleNewClient(tcpClient); handleNewClient(tcpClient);
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
} }
#endif #endif
} }
@ -923,7 +925,7 @@ void WebSocketsServer::begin(void) {
void WebSocketsServer::close(void) { void WebSocketsServer::close(void) {
WebSocketsServerCore::close(); WebSocketsServerCore::close();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
_server->close(); _server->close();
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) #elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server->end(); _server->end();

View File

@ -90,7 +90,7 @@ class WebSocketsServerCore : protected WebSockets {
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
void disableHeartbeat(); void disableHeartbeat();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_RP2040)
IPAddress remoteIP(uint8_t num); IPAddress remoteIP(uint8_t num);
#endif #endif

View File

@ -9,7 +9,7 @@ For details, see http://sourceforge.net/projects/libb64
#include <core_esp8266_features.h> #include <core_esp8266_features.h>
#endif #endif
#if defined(ESP32) #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
#define CORE_HAS_LIBB64 #define CORE_HAS_LIBB64
#endif #endif

View File

@ -9,7 +9,7 @@ For details, see http://sourceforge.net/projects/libb64
#include <core_esp8266_features.h> #include <core_esp8266_features.h>
#endif #endif
#if defined(ESP32) #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
#define CORE_HAS_LIBB64 #define CORE_HAS_LIBB64
#endif #endif