Unverified Commit 7180ca3b authored by Juraj Andrássy's avatar Juraj Andrássy Committed by GitHub

Add ESP32-based WiFi support via lwIP_ESPHost library (#1950)

parent c64a4a58
......@@ -32,6 +32,8 @@
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
#include <pico/cyw43_arch.h>
static CYW43lwIP _wifi(1);
#elif defined(ESPHOSTSPI)
static ESPHostLwIP _wifi;
#else
static NoDriverLwIP _wifi;
#endif
......@@ -100,11 +102,11 @@ int WiFiClass::begin(const char* ssid, const char *passphrase, const uint8_t *bs
} else {
bzero(_bssid, sizeof(_bssid));
}
_wifi.setSTA();
_wifi.setSSID(_ssid.c_str());
_wifi.setBSSID(_bssid);
_wifi.setPassword(passphrase);
_wifi.setTimeout(_timeout);
_wifi.setSTA();
_apMode = false;
_wifiHWInitted = true;
uint32_t start = millis(); // The timeout starts from network init, not network link up
......@@ -139,10 +141,10 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
_ssid = ssid;
_password = passphrase;
_wifi.setAP();
_wifi.setSSID(_ssid.c_str());
_wifi.setPassword(passphrase);
_wifi.setTimeout(_timeout);
_wifi.setAP();
_apMode = true;
IPAddress gw = _wifi.gatewayIP();
if (!gw.isSet()) {
......
......@@ -25,6 +25,8 @@
#include <Arduino.h>
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
#include <lwIP_CYW43.h>
#elif defined(ESPHOSTSPI)
#include <lwIP_ESPHost.h>
#else
#include "utility/lwIP_nodriver.h"
#endif
......
# lwIP_ESPHost library
RP2040 Arduino integration with the ESPHost library.
[ESPHost library](https://github.com/JAndrassy/ESPHost) is a driver for communication with Espressif's esp-hosted-fg firmware.
name=lwIP_ESPHost
version=1
author=Juraj Andrassy
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
sentence=RP2040 ESPHost wifi driver
paragraph=Driver for the esp-hosted-fg firmware with the ESPHosted library
category=Communication
url=https://github.com/earlephilhower/arduino-pico
architectures=rp2040
dot_a_linkage=true
/*
WiFi <-> LWIP for ESPHost library in RP2040 Core
Copyright (c) 2024 Juraj Andrassy
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 "ESPHost.h"
#include "CEspControl.h"
ESPHost::ESPHost(int8_t cs, arduino::SPIClass &spi, int8_t intrpin) {
(void) cs;
(void) spi;
(void) intrpin;
// CS and SPI are configured in ESPHost library
}
bool ESPHost::begin(const uint8_t *address, netif *netif) {
(void) address;
(void) netif;
// WiFi is initialized in ESPHostLwIP
return true;
}
void ESPHost::end() {
// WiFi is ended in ESPHostLwIP
}
uint16_t ESPHost::sendFrame(const uint8_t *data, uint16_t datalen) {
int res = CEspControl::getInstance().sendBuffer(apMode ? ESP_AP_IF : ESP_STA_IF, 0, (uint8_t*) data, datalen);
CEspControl::getInstance().communicateWithEsp();
return (res == ESP_CONTROL_OK) ? datalen : 0;
}
uint16_t ESPHost::readFrameData(uint8_t *buffer, uint16_t bufsize) {
uint8_t ifn = 0;
uint16_t res;
if (apMode) {
res = CEspControl::getInstance().getSoftApRx(ifn, buffer, bufsize);
} else {
res = CEspControl::getInstance().getStationRx(ifn, buffer, bufsize);
}
return res;
}
uint16_t ESPHost::readFrameSize() {
CEspControl::getInstance().communicateWithEsp();
uint16_t res;
if (apMode) {
res = CEspControl::getInstance().peekSoftApRxPayloadLen();
} else {
res = CEspControl::getInstance().peekStationRxPayloadLen();
}
return res;
}
/*
WiFi <-> LWIP for ESPHost library in RP2040 Core
Copyright (c) 2024 Juraj Andrassy
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
*/
#pragma once
#include <Arduino.h>
#include <SPI.h>
class ESPHost {
public:
// constructor and methods as required by LwipIntfDev
ESPHost(int8_t cs, arduino::SPIClass &spi, int8_t intrpin);
bool begin(const uint8_t *address, netif *netif);
void end();
uint16_t sendFrame(const uint8_t *data, uint16_t datalen);
uint16_t readFrameData(uint8_t *buffer, uint16_t bufsize);
uint16_t readFrameSize();
void discardFrame(uint16_t ign) {
(void) ign;
}
bool interruptIsPossible() {
return false;
}
constexpr bool needsSPI() const {
return false;
}
protected:
bool apMode = false;
};
/*
WiFi <-> LWIP for ESPHost library in RP2040 Core
Copyright (c) 2024 Juraj Andrassy
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 "lwIP_ESPHost.h"
#include "CEspControl.h"
#define MAX_SOFTAP_CONNECTION_DEF 5
bool ESPHostLwIP::wifiHwInitialized = false;
ESPHostLwIP* ESPHostLwIP::instance = nullptr;
void ESPHostLwIP::setSTA() {
apMode = false;
}
void ESPHostLwIP::setAP() {
apMode = true;
}
void ESPHostLwIP::setSSID(const char *ssid) {
if (apMode) {
if (ssid == nullptr) {
softAP.ssid[0] = 0;
} else {
memcpy(softAP.ssid, ssid, sizeof(softAP.ssid));
}
} else {
if (ssid == nullptr) {
ap.ssid[0] = 0;
} else {
memcpy(ap.ssid, ssid, sizeof(ap.ssid));
}
}
}
void ESPHostLwIP::setBSSID(const uint8_t *bssid) {
if (bssid == nullptr) {
ap.bssid[0] = 0;
} else {
memcpy(ap.bssid, bssid, sizeof(ap.bssid));
}
}
void ESPHostLwIP::setPassword(const char *pass) {
if (apMode) {
if (pass == nullptr) {
softAP.pwd[0] = 0;
} else {
memcpy(softAP.pwd, pass, sizeof(softAP.pwd));
}
} else {
if (pass == nullptr) {
ap.pwd[0] = 0;
} else {
memcpy(ap.pwd, pass, sizeof(ap.pwd));
}
}
}
void ESPHostLwIP::setChannel(uint8_t channel) {
softAP.channel = (channel > MAX_CHNL_NO) ? MAX_CHNL_NO : channel;
}
void ESPHostLwIP::setTimeout(int _timeout) {
timeout = _timeout;
}
int ESPHostLwIP::initEventCb(CCtrlMsgWrapper *resp) {
(void) resp;
wifiHwInitialized = true;
return ESP_CONTROL_OK;
}
int ESPHostLwIP::disconnectEventCb(CCtrlMsgWrapper *resp) {
(void) resp;
instance->onDisconnectEvent();
return ESP_CONTROL_OK;
}
bool ESPHostLwIP::initHW() {
if (wifiHwInitialized)
return true;
instance = this;
CEspControl::getInstance().listenForStationDisconnectEvent(disconnectEventCb);
CEspControl::getInstance().listenForInitEvent(initEventCb);
if (CEspControl::getInstance().initSpiDriver() != 0)
return false;
uint32_t start = millis();
while (!wifiHwInitialized && (millis() - start < timeout)) {
CEspControl::getInstance().communicateWithEsp();
delay(100);
}
if (wifiHwInitialized) {
wifiStatus = WL_IDLE_STATUS;
}
__startEthernetContext();
return wifiHwInitialized;
}
bool ESPHostLwIP::begin() {
if (!initHW())
return false;
ethernet_arch_lwip_begin();
if (!apMode) {
CEspControl::getInstance().setWifiMode(WIFI_MODE_STA);
if (CEspControl::getInstance().connectAccessPoint(ap) != ESP_CONTROL_OK) {
wifiStatus = WL_CONNECT_FAILED;
ethernet_arch_lwip_end();
return false;
}
CEspControl::getInstance().getAccessPointConfig(ap);
} else {
CEspControl::getInstance().setWifiMode(WIFI_MODE_AP);
if (softAP.channel == 0 || softAP.channel > MAX_CHNL_NO) {
softAP.channel = 1;
}
softAP.max_connections = MAX_SOFTAP_CONNECTION_DEF;
softAP.encryption_mode = softAP.pwd[0] == 0 ? WIFI_AUTH_OPEN : WIFI_AUTH_WPA_WPA2_PSK;
softAP.bandwidth = WIFI_BW_HT40;
softAP.ssid_hidden = false;
int rv = CEspControl::getInstance().startSoftAccessPoint(softAP);
if (rv != ESP_CONTROL_OK) {
wifiStatus = WL_AP_FAILED;
ethernet_arch_lwip_end();
return false;
}
CEspControl::getInstance().getSoftAccessPointConfig(softAP);
}
ethernet_arch_lwip_end();
uint8_t mac[6];
if (!LwipIntfDev<ESPHost>::begin(macAddress(apMode, mac))) {
ethernet_arch_lwip_begin();
if (apMode) {
CEspControl::getInstance().stopSoftAccessPoint();
wifiStatus = WL_AP_FAILED;
} else {
CEspControl::getInstance().disconnectAccessPoint();
wifiStatus = WL_CONNECT_FAILED;
}
ethernet_arch_lwip_end();
return false;
}
if (apMode) {
wifiStatus = WL_AP_LISTENING;
} else {
joined = true;
wifiStatus = LwipIntfDev<ESPHost>::connected() ? WL_CONNECTED : WL_DISCONNECTED;
}
return true;
}
void ESPHostLwIP::end() {
LwipIntfDev<ESPHost>::end();
if (apMode) {
CEspControl::getInstance().stopSoftAccessPoint();
} else {
CEspControl::getInstance().disconnectAccessPoint();
joined = false;
}
wifiStatus = WL_IDLE_STATUS;
}
void ESPHostLwIP::onDisconnectEvent() {
LwipIntfDev<ESPHost>::end();
joined = false;
wifiStatus = WL_CONNECTION_LOST;
}
bool ESPHostLwIP::connected() {
return (status() == WL_CONNECTED);
}
uint8_t ESPHostLwIP::status() {
initHW();
if (joined && wifiStatus == WL_DISCONNECTED && LwipIntfDev<ESPHost>::connected()) {
wifiStatus = WL_CONNECTED; // DHCP finished
}
return wifiStatus;
}
uint8_t* ESPHostLwIP::macAddress(bool apMode, uint8_t *mac) {
if (!initHW())
return mac;
WifiMac_t MAC;
MAC.mode = apMode ? WIFI_MODE_AP : WIFI_MODE_STA;
ethernet_arch_lwip_begin();
if (CEspControl::getInstance().getWifiMacAddress(MAC) == ESP_CONTROL_OK) {
CNetUtilities::macStr2macArray(mac, MAC.mac);
}
ethernet_arch_lwip_end();
return mac;
}
uint8_t* ESPHostLwIP::BSSID(uint8_t *bssid) {
CNetUtilities::macStr2macArray(bssid, (char*) ap.bssid);
return bssid;
}
int ESPHostLwIP::channel() {
return ap.channel;
}
int32_t ESPHostLwIP::RSSI() {
if (!joined)
return 0;
ethernet_arch_lwip_begin();
CEspControl::getInstance().getAccessPointConfig(ap);
ethernet_arch_lwip_end();
return ap.rssi;
}
static uint8_t encr2wl_enc(int enc) {
// the ESPHost returns authentication mode as encryption mode
if (enc == WIFI_AUTH_OPEN) {
return ENC_TYPE_NONE;
} else if (enc == WIFI_AUTH_WEP) {
return ENC_TYPE_WEP;
} else if (enc == WIFI_AUTH_WPA_PSK) {
return ENC_TYPE_WPA;
} else if (enc == WIFI_AUTH_WPA2_PSK) {
return ENC_TYPE_WPA2;
} else if (enc == WIFI_AUTH_WPA_WPA2_PSK) {
return ENC_TYPE_WPA2;
} else if (enc == WIFI_AUTH_WPA3_PSK) {
return ENC_TYPE_WPA3;
} else if (enc == WIFI_AUTH_WPA2_WPA3_PSK) {
return ENC_TYPE_WPA3;
} else {
return ENC_TYPE_UNKNOWN;
}
}
uint8_t ESPHostLwIP::encryptionType() {
return encr2wl_enc(ap.encryption_mode);
}
int8_t ESPHostLwIP::scanNetworks(bool async) {
accessPoints.clear();
if (!initHW())
return -1;
ethernet_arch_lwip_begin();
int res = CEspControl::getInstance().getAccessPointScanList(accessPoints);
ethernet_arch_lwip_end();
wifiStatus = WL_SCAN_COMPLETED;
if (res != ESP_CONTROL_OK)
return -1;
return accessPoints.size();
}
int8_t ESPHostLwIP::scanComplete() {
return accessPoints.size();
}
void ESPHostLwIP::scanDelete() {
accessPoints.clear();
}
const char* ESPHostLwIP::SSID(uint8_t networkItem) {
if (networkItem < accessPoints.size()) {
return (const char*) accessPoints[networkItem].ssid;
}
return nullptr;
}
uint8_t ESPHostLwIP::encryptionType(uint8_t networkItem) {
if (networkItem < accessPoints.size()) {
return encr2wl_enc(accessPoints[networkItem].encryption_mode);
}
return ENC_TYPE_UNKNOWN;
}
uint8_t* ESPHostLwIP::BSSID(uint8_t networkItem, uint8_t *bssid) {
if (networkItem < accessPoints.size()) {
CNetUtilities::macStr2macArray(bssid, (char*) accessPoints[networkItem].bssid);
}
return bssid;
}
uint8_t ESPHostLwIP::channel(uint8_t networkItem) {
if (networkItem < accessPoints.size()) {
return accessPoints[networkItem].channel;
}
return 0;
}
int32_t ESPHostLwIP::RSSI(uint8_t networkItem) {
if (networkItem < accessPoints.size()) {
return accessPoints[networkItem].rssi;
}
return 0;
}
void ESPHostLwIP::lowPowerMode() {
if (!initHW())
return;
ethernet_arch_lwip_begin();
CEspControl::getInstance().setPowerSaveMode(1);
ethernet_arch_lwip_end();
}
void ESPHostLwIP::noLowPowerMode() {
// not supported by firmware
}
/*
WiFi <-> LWIP for ESPHost library in RP2040 Core
Copyright (c) 2024 Juraj Andrassy
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
*/
#pragma once
#include <LwipIntfDev.h>
#include "CCtrlWrapper.h"
#include "ESPHost.h"
class ESPHostLwIP : public LwipIntfDev<ESPHost> {
public:
void setSTA();
void setAP();
void setSSID(const char *p);
void setBSSID(const uint8_t *bssid);
void setPassword(const char *p);
void setChannel(uint8_t channel);
bool begin();
void end();
bool connected();
uint8_t status();
uint8_t* macAddress(bool apMode, uint8_t *mac);
uint8_t* BSSID(uint8_t *bssid);
int32_t RSSI();
int channel();
uint8_t encryptionType();
int8_t scanNetworks(bool async = false);
int8_t scanComplete();
void scanDelete();
const char* SSID(uint8_t networkItem);
uint8_t encryptionType(uint8_t networkItem);
uint8_t* BSSID(uint8_t networkItem, uint8_t *bssid);
uint8_t channel(uint8_t networkItem);
int32_t RSSI(uint8_t networkItem);
void lowPowerMode();
void noLowPowerMode();
void setTimeout(int timeout);
private:
static int initEventCb(CCtrlMsgWrapper *resp);
static int disconnectEventCb(CCtrlMsgWrapper *resp);
static bool wifiHwInitialized;
static ESPHostLwIP* instance;
bool initHW();
void onDisconnectEvent();
uint32_t timeout = 10000;
uint8_t wifiStatus = WL_NO_MODULE;
WifiApCfg_t ap;
bool joined = false;
SoftApCfg_t softAP;
std::vector<AccessPoint_t> accessPoints;
}
;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment