423 lines
19 KiB
C++
Vendored
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 ¶m1, int diskNo);
|
|
bool setQuickDiskFile(const std::string ¶m1, int diskNo);
|
|
bool setRamFile(const std::string ¶m1, 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
|