Files
2026-04-30 08:58:26 +01:00

423 lines
19 KiB
C++
Vendored

/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Name: WiFi.h
// Created: Sep 2024
// Version: v1.0
// Author(s): Philip Smart
// Description: Header for the WiFi AP/Client logic.
// Credits:
// Copyright: (c) 2019-2026 Philip Smart <philip.smart@net2net.org>
//
// History: Sep 2024 - Initial write based on the pz80 WiFi class.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef WIFI_H
#define WIFI_H
#if defined(CONFIG_IF_WIFI_ENABLED) || defined(CONFIG_IF_USB_NCM_ENABLED)
#include "freertos/event_groups.h"
#include "esp_system.h"
#if defined(CONFIG_IF_WIFI_ENABLED)
#include "esp_wifi.h"
#endif
#include "esp_event.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include <esp_http_server.h>
#include "hal/gpio_hal.h"
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <memory>
#include <arpa/inet.h>
#include "NVS.h"
#include "SDCard.h"
#include "IO.h"
extern "C"
{
#include "flash_ram.h"
}
#include "cJSON.h"
#include "FSPI.h"
// Encapsulate the WiFi functionality.
class WiFi
{
// Private Constants.
static constexpr float WIFI_VERSION = 1.10;
static constexpr const char *WIFI_RECOVERY_FILE_DIR = "/recovery";
static constexpr const char *WIFI_RECOVERY_FILE = "tzpuPico_Install.tar.gz";
static constexpr const char *WIFI_AP_DEFAULT_IP = "192.168.4.1";
static constexpr const char *WIFI_AP_DEFAULT_GW = "192.168.4.1";
static constexpr const char *WIFI_AP_DEFAULT_NETMASK = "255.255.255.0";
static constexpr const char *WIFI_TEMP_DIR = "/tmp";
static constexpr const char *WIFI_RP2350_FW_FILENAME = "rp2350fw.bin";
static constexpr const char *WIFI_FILEPACK_FILENAME = "filepack";
static constexpr uint32_t WIFI_RP2350_FLASH_LOAD_ADDR = 0x10020000; // Address is after the bootloader which is 128K in size.
static constexpr uint32_t WIFI_RP2350_FLASH_SIZE = 0x1000000 - 65536; // 16MB - Bootloader.
static constexpr uint32_t WIFI_RP2350_BIN_CHECK_ADDR = 0x0124; // Address in binary to check for signature 0xF2EB8871
static constexpr uint32_t WIFI_RP2350_BIN_CHECK_SIGNATURE = 0x7188EBF2; // Binary confirmation signature LSB.
static constexpr uint32_t WIFI_RP2350_UPDATE_ID = 0xFAE5D7B1; // Code which when received indicates a firmware update is required.
static constexpr uint32_t WIFI_RP2350_CFGCLEAR_ID = 0xB1D7E5FA; // Code which when received indicates config should be cleared on firmware update.
static constexpr uint32_t WIFI_RP2350_HDRCLEAR_ID = 0xC2E8F6AB; // Code which when received indicates flash header should be reset on firmware update.
static constexpr uint32_t WIFI_RP2350_SECTOR_SIZE = 4096; // Size of a flashram sector.
static constexpr uint32_t WIFI_RP2350_PAGE_SIZE = 256; // Size of a flashram update page size.
static constexpr uint8_t WIFI_RP2350_RESP_CANCEL = 0xFF; // Firmware update response code cancel.
static constexpr uint8_t WIFI_RP2350_RESP_FW_OK = 0xF8; // Firmware update successful.
static constexpr uint8_t WIFI_RP2350_RESP_FW_CHKERR = 0xF7; // Firmware checksum mismatch.
static constexpr uint8_t WIFI_RP2350_RESP_FLASH_NOK = 0xF6; // Frame acknowledge.
static constexpr uint8_t WIFI_RP2350_RESP_FLASH_OK = 0xF5; // Frame acknowledge.
static constexpr uint8_t WIFI_RP2350_RESP_FRAME_ADDRERR = 0xF4; // Programming address error.
static constexpr uint8_t WIFI_RP2350_RESP_FRAME_CHKERR = 0xF3; // Frame checksum error.
static constexpr uint8_t WIFI_RP2350_RESP_FRAME_OK = 0xF2; // Frame acknowledge.
static constexpr uint8_t WIFI_RP2350_RESP_ID_OK = 0xF1; // ID ok, entering update mode.
static constexpr int WIFI_RP2350_MAX_RETRIES = 10; // Maximum number of resend retries.
static constexpr uint64_t WIFI_RP2350_RETRY_TIMEOUT = 2000000; // Response before retry timeout.
static constexpr uint64_t WIFI_RP2350_RETRYAUTH_TIMEOUT = 2000000; // Authenticate mode retry timeout.
static constexpr uint64_t WIFI_RP2350_AUTH_TIMEOUT = WIFI_RP2350_MAX_RETRIES * WIFI_RP2350_RETRYAUTH_TIMEOUT; // Authenticate mode expiration timeout.
static constexpr uint64_t WIFI_RP2350_FRAME_TIMEOUT = WIFI_RP2350_MAX_RETRIES * WIFI_RP2350_RETRY_TIMEOUT; // Frame response timeout.
static constexpr uint64_t WIFI_RP2350_FLASH_TIMEOUT = 5000000; // Flash programming response timeout.
static constexpr int WIFI_MAX_FLOPPY_DISK_IMAGES = 2; // Number of active floppy disks being serviced to the RP2350 emulation.
static constexpr int WIFI_MAX_QUICK_DISK_IMAGES = 1; // Number of active Quick disks being serviced to the RP2350 emulation.
static constexpr int WIFI_MAX_RAMFILE_IMAGES = 4; // Number of possible RAMFILE boards requiring backup image files.
// The event group allows multiple bits for each event, but we only care about two events:
// - we are connected to the AP with an IP
// - we failed to connect after the maximum amount of retries
static constexpr int WIFI_CONNECTED_BIT = BIT0;
static constexpr int WIFI_FAIL_BIT = BIT1;
// Tag for ESP WiFi logging.
static constexpr const char *WIFITAG = "WiFi";
// Menu selection types.
enum WIFIMODES
{
WIFI_OFF = 0x00, // WiFi is disabled.
WIFI_ON = 0x01, // WiFi is enabled.
WIFI_CONFIG_AP = 0x02, // WiFi is set to enable Access Point to configure WiFi settings.
WIFI_CONFIG_CLIENT = 0x03 // WiFi is set to enable Client mode using persisted settings.
};
// Possible types of drive which can be connected.
enum DRIVETYPES
{
FLOPPY_DISK = 0x00, // Floppy disk drive.
QUICK_DISK = 0x01, // 2.5" Quick disk drive.
RAMFILE = 0x02, // 32K RAMFILE Board Image.
};
// Default WiFi parameters.
static constexpr size_t MAX_WIFI_SSID_LEN = 31;
static constexpr size_t MAX_WIFI_PWD_LEN = 63;
static constexpr size_t MAX_WIFI_IP_LEN = 15;
static constexpr size_t MAX_WIFI_NETMASK_LEN = 15;
static constexpr size_t MAX_WIFI_GATEWAY_LEN = 15;
static constexpr size_t MAX_WEBFS_LEN = 32;
// Buffer size for sending file data in chunks to the browser.
static constexpr size_t MAX_CHUNK_SIZE = 4096;
// Max length a file path can have on the embedded storage device.
static constexpr size_t FILE_PATH_MAX = (15 + 128);
public:
// Public constants.
static constexpr int OBJECT_VERSION_LIST_MAX = 18;
static constexpr const char *FILEPACK_VERSION_FILE = "filepack_version.txt";
static constexpr const char *WIFI_WEBFS_PATH = "/webfs";
static constexpr const char *WEBFS_VERSION_FILE = "webfs_version.txt";
// Types for holding and maintaining a class/object to version number array.
typedef struct
{
std::string object;
float version;
} t_versionItem;
typedef struct
{
int elements;
t_versionItem *item[OBJECT_VERSION_LIST_MAX];
} t_versionList;
// Prototypes.
WiFi(bool defaultMode, uint16_t device, NVS *nvs, SDCard *sdcard, cJSON *config, const char *fsPath, t_versionList *versionList);
WiFi(void);
~WiFi(void);
#if defined(CONFIG_IF_WIFI_ENABLED)
void run(void);
#endif
void init(bool defaultMode, uint16_t device, NVS *nvs, SDCard *sdcard, cJSON *config, const char *fsPath, t_versionList *versionList);
void readRP2350Info(const std::string &inParam, FSPI &fspi);
bool doReboot(void);
void resetRP2350(bool uploadMode, bool disableUpload);
bool setFloppyDiskFile(const std::string &param1, int diskNo);
bool setQuickDiskFile(const std::string &param1, int diskNo);
bool setRamFile(const std::string &param1, int ramfileNo);
bool startWebserver(void);
// Non Volatile Storage handle.
NVS *nvs;
// SD Card object.
SDCard *sdcard;
// Method to return the class version number.
float version(void)
{
// Locals.
float retVal = WIFI_VERSION;
return retVal;
}
protected:
private:
// Type for key:value pairs.
typedef struct
{
std::string name;
std::string value;
} t_kvPair;
// Structure to maintain wifi configuration data. This data is persisted through powercycles as needed.
typedef struct
{
// Client access parameters, these, when valid, are used for binding to a known wifi access point.
struct
{
bool valid;
char ssid[MAX_WIFI_SSID_LEN + 1];
char pwd[MAX_WIFI_PWD_LEN + 1];
bool useDHCP;
char ip[MAX_WIFI_IP_LEN + 1];
char netmask[MAX_WIFI_NETMASK_LEN + 1];
char gateway[MAX_WIFI_GATEWAY_LEN + 1];
} clientParams;
// Structure to maintain Access Point parameters. These are configurable to allow possibility of changing them.
struct
{
char ssid[MAX_WIFI_SSID_LEN + 1];
char pwd[MAX_WIFI_PWD_LEN + 1];
char ip[MAX_WIFI_IP_LEN + 1];
char netmask[MAX_WIFI_NETMASK_LEN + 1];
char gateway[MAX_WIFI_GATEWAY_LEN + 1];
} apParams;
// General runtime control parameters.
struct
{
enum WIFIMODES wifiMode;
int8_t txPower; // WiFi TX power in 0.25dBm units (8=2dBm, 40=10dBm, 80=20dBm). 0 = use default.
} params;
} t_wifiConfig;
// Configuration data.
t_wifiConfig wifiConfig;
// Structure to manage the WiFi control variables, signifying the state of the Client or Access Point, runtime dependent, and
// necessary dedicated run variables (as opposed to locals).
typedef struct
{
// Client mode variables, active when in client mode.
struct
{
int clientRetryCnt;
bool connected;
char ssid[MAX_WIFI_SSID_LEN + 1];
char pwd[MAX_WIFI_PWD_LEN + 1];
char ip[MAX_WIFI_IP_LEN + 1];
char netmask[MAX_WIFI_IP_LEN + 1];
char gateway[MAX_WIFI_IP_LEN + 1];
} client;
// Access Point mode variabls, active when in AP mode.
struct
{
char ssid[MAX_WIFI_SSID_LEN + 1];
char pwd[MAX_WIFI_PWD_LEN + 1];
char ip[MAX_WIFI_IP_LEN + 1];
char netmask[MAX_WIFI_IP_LEN + 1];
char gateway[MAX_WIFI_IP_LEN + 1];
} ap;
// HTTP session variables, parsed out of incoming connections. The sessions are synchronous so only maintain
// one copy.
struct
{
std::string host;
std::string fileName;
std::string filePath;
bool gzip;
bool deflate;
} session;
// Runtime variables, used for global control of the WiFi module.
struct
{
// Default path on the underlying filesystem. This is where the NVS/SD partition is mounted and all files under this directory are accessible.
char fsPath[FILE_PATH_MAX + 1];
// Version list of all objects used to build the pz80 interface along with their version numbers.
t_versionList *versionList;
// Run mode of the Wifi: Off, On or Access Point.
enum WIFIMODES wifiMode;
// Name of the main web filesystem on the SD card.
char webfs[MAX_WEBFS_LEN + 1];
// Handle to http server.
httpd_handle_t server;
// Class name, used for NVS keys.
std::string thisClass;
// Device id - underlying host processor type.
uint16_t hostDevice;
// Device name. Underlying host processor name.
std::string hostDeviceName;
// Device display name. Underlying host processor display name.
std::string hostDeviceDisplayName;
// Flag to raise a reboot button on the displayed page.
bool rebootButton;
// Flag to indicate a hard reboot needed.
bool reboot;
// Base path of file storag.
char basePath[FILE_PATH_MAX];
// String to hold any response error message.
std::string errorMsg;
// Buffer to create response or command messages to be sent to rp2350.
char *ioBuf;
// RP2350 configuration.
t_FlashPartitionHeader rp2350FlashHeader;
int32_t rp2350CpuFreq; // RP2350 CPU freq in Hz (from INF)
int32_t rp2350PsramFreq; // PSRAM freq in Hz (from INF)
int32_t rp2350Voltage; // Core voltage (from INF)
uint32_t rp2350FlashSize; // RP2350 Flash size in bytes (from INF)
uint32_t rp2350PsramSize; // RP2350 PSRAM size in bytes (from INF)
uint32_t rp2350HostClkHz; // Measured host clock frequency in Hz (from INF)
uint32_t rp2350EmulSpeedHz; // Effective Z80 emulation speed in Hz (from INF)
char rp2350DriverSummary[FLASHHDR_DRIVER_SUMMARY_SIZE]; // Active drivers (from INF)
// Active Floppy Disk images.
std::string floppyDiskImage[WIFI_MAX_FLOPPY_DISK_IMAGES];
// Active Quick Disk images.
std::string quickDiskImage[WIFI_MAX_QUICK_DISK_IMAGES];
// Active RAMFILE image.
std::string ramFileImage[WIFI_MAX_RAMFILE_IMAGES];
// Active disk during configuration/setup.
int activeDiskImageNo;
// Active RAMFILE image during configuration/setup.
int activeRamFileImageNo;
} run;
} t_wifiControl;
// Control data.
t_wifiControl wifiCtrl;
// Prototypes.
#if defined(CONFIG_IF_WIFI_ENABLED)
bool setupWifiClient(void);
bool setupWifiAP(void);
bool stopWifi(void);
#endif
void stopWebserver(void);
float getVersionNumber(const std::string &name);
esp_err_t expandAndSendFile(httpd_req_t *req, const char *basePath, const std::string &fileName);
esp_err_t expandVarsAndSend(httpd_req_t *req, std::string str);
esp_err_t wifiDataPOSTHandler(httpd_req_t *req, const std::vector<t_kvPair> &pairs, std::string &resp);
esp_err_t uploadFileHandler(httpd_req_t *req, std::string &file, std::string &resp);
esp_err_t downloadFileHandler(httpd_req_t *req, std::string &directory, std::string &filename, std::string &resp);
esp_err_t reqRP2350FWUpdate(char *errMsg,
std::ifstream &inFile,
uint32_t fileSize,
uint8_t instance,
uint8_t clearCfg,
uint8_t clearFlashHdr,
char *license,
char *author,
char *description,
char *version,
char *versionDate,
char *copyright,
uint32_t fwChkSum);
esp_err_t sendFileManagerDir(httpd_req_t *req);
esp_err_t unpackFile(const std::string &srcDir, const std::string &srcFile, const std::string &dstDir, const std::string &dstFile);
esp_err_t getPOSTData(httpd_req_t *req, std::vector<t_kvPair> *pairs);
esp_err_t versionedRename(const std::string &src, const std::string &dst, std::string &errMsg);
bool isFileExt(const std::string &fileName, const std::string &extension);
esp_err_t setContentTypeFromFileType(httpd_req_t *req, const std::string &fileName);
esp_err_t getPathFromURI(std::string &destPath, std::string &destFile, const char *basePath, const char *uri);
esp_err_t getPathFromURI(std::string &destPath, const char *basePath, const char *uri);
std::string esp32PartitionType(esp_partition_type_t type);
std::string esp32PartitionSubType(esp_partition_subtype_t subtype);
std::string urlDecode(const std::string &str);
std::string urlDecode(const char *buf);
std::string urlEncode(const std::string &str);
std::string escapeHTML(const std::string &input);
void splitURI(httpd_req_t *req, std::string &uri, std::string &url, std::string &urq, std::vector<t_kvPair> &pairs);
std::vector<std::string> split(const std::string &s, const std::string &delimiter);
std::vector<std::string> split(const std::string &str, char delim);
bool isNumber(const std::string &str);
bool stringReplace(std::string &str, const std::string &from, const std::string &to);
bool validateIP(const std::string &ip);
bool splitIP(const std::string &ip, int *a, int *b, int *c, int *d);
void logError(const char *msg, esp_err_t err = ESP_OK);
void reloadRP2350Config(void);
static bool isValidPath(const char *path, const char *mountPath);
static esp_err_t listDirectoryHandler(httpd_req_t *req);
static esp_err_t changeDiskHandler(httpd_req_t *req, enum DRIVETYPES driveType);
static esp_err_t defaultDataPOSTHandler(httpd_req_t *req);
static esp_err_t defaultDataGETHandler(httpd_req_t *req);
static esp_err_t otaFetchFile(httpd_req_t *req, const std::string &createFileName);
static esp_err_t otaFetchFile(httpd_req_t *req, const std::string &createFileName, const std::string &fileDir);
static esp_err_t otaESP32FirmwareUpdatePOSTHandler(httpd_req_t *req);
static esp_err_t otaRP2350FirmwareUpdatePOSTHandler(httpd_req_t *req);
static esp_err_t otaFilepackUpdatePOSTHandler(httpd_req_t *req);
static esp_err_t defaultRebootHandler(httpd_req_t *req);
static esp_err_t defaultTasksHandler(httpd_req_t *req);
static esp_err_t defaultRecoverHandler(httpd_req_t *req);
static esp_err_t defaultFileHandler(httpd_req_t *req);
#if defined(CONFIG_IF_WIFI_ENABLED)
static void wifiAPHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
static void wifiClientHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
#endif
};
#endif
#endif // WIFI_H