⚡ Full migration to esp-idf
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <settings/ap_settings.h>
|
||||
#include <utils/timing.h>
|
||||
#include <WiFi.h>
|
||||
#include "esp_timer.h"
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <wifi/dns_server.h>
|
||||
#include <esp_timer.h>
|
||||
#include <string>
|
||||
|
||||
class APService : public StatefulService<APSettings> {
|
||||
public:
|
||||
@@ -28,8 +30,8 @@ class APService : public StatefulService<APSettings> {
|
||||
DNSServer *_dnsServer;
|
||||
|
||||
volatile unsigned long _lastManaged;
|
||||
volatile boolean _reconfigureAp;
|
||||
volatile boolean _recoveryMode = false;
|
||||
volatile bool _reconfigureAp;
|
||||
volatile bool _recoveryMode = false;
|
||||
|
||||
void reconfigureAP();
|
||||
void manageAP();
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CONFIG_HTTPD_WS_SUPPORT
|
||||
#define CONFIG_HTTPD_WS_SUPPORT 1
|
||||
#endif
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cstdint>
|
||||
#include <communication/webserver.h>
|
||||
#include <communication/comm_base.hpp>
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
#ifndef PGM_P
|
||||
#define PGM_P const char *
|
||||
#endif
|
||||
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||
#endif
|
||||
|
||||
#ifndef pgm_read_word
|
||||
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
|
||||
#endif
|
||||
|
||||
#ifndef pgm_read_dword
|
||||
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <esp_http_server.h>
|
||||
#include "platform_shared/message.pb.h"
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <LittleFS.h>
|
||||
#include <esp_littlefs.h>
|
||||
#include <esp_vfs.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <platform_shared/api.pb.h>
|
||||
|
||||
#define ESP_FS LittleFS
|
||||
#define MOUNT_POINT "/littlefs"
|
||||
|
||||
#define FS_CONFIG_DIRECTORY "/config"
|
||||
#define DEVICE_CONFIG_FILE "/config/peripheral.json"
|
||||
@@ -24,6 +28,25 @@ void listFilesProto(const std::string &directory, api_FileEntry *entry);
|
||||
std::string listFiles(const std::string &directory, bool isRoot = true);
|
||||
bool deleteFile(const char *filename);
|
||||
bool editFile(const char *filename, const uint8_t *content, size_t size);
|
||||
#define AP_SETTINGS_FILE MOUNT_POINT "/config/apSettings.json"
|
||||
#define CAMERA_SETTINGS_FILE MOUNT_POINT "/config/cameraSettings.json"
|
||||
#define FS_CONFIG_DIRECTORY MOUNT_POINT "/config"
|
||||
#define DEVICE_CONFIG_FILE MOUNT_POINT "/config/peripheral.json"
|
||||
#define WIFI_SETTINGS_FILE MOUNT_POINT "/config/wifiSettings.json"
|
||||
#define SERVO_SETTINGS_FILE MOUNT_POINT "/config/servoSettings.json"
|
||||
#define MDNS_SETTINGS_FILE MOUNT_POINT "/config/mdnsSettings.json"
|
||||
|
||||
namespace FileSystem {
|
||||
|
||||
bool init();
|
||||
|
||||
std::string listFiles(const std::string &directory, bool isRoot = true);
|
||||
bool deleteFile(const char *filename);
|
||||
bool editFile(const char *filename, const char *content);
|
||||
bool fileExists(const char *filename);
|
||||
std::string readFile(const char *filename);
|
||||
bool writeFile(const char *filename, const char *content);
|
||||
bool mkdirRecursive(const char *path);
|
||||
|
||||
esp_err_t getFilesProto(httpd_req_t *request);
|
||||
esp_err_t getFiles(httpd_req_t *request);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <LittleFS.h>
|
||||
#include <platform_shared/message.pb.h>
|
||||
#include <filesystem.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
|
||||
// Make sure that this aligns with socket_message.FSDownloadData.data max_size (and for upload)
|
||||
#define FS_MAX_CHUNK_SIZE 16384 // ~= 16 kb
|
||||
#define FS_TRANSFER_TIMEOUT_MS 30000 // 30 seconds
|
||||
#define FS_MAX_CHUNK_SIZE 16384
|
||||
#define FS_TRANSFER_TIMEOUT_MS 30000
|
||||
|
||||
namespace FileSystemWS {
|
||||
|
||||
struct DownloadState {
|
||||
std::string path;
|
||||
File file;
|
||||
FILE* file;
|
||||
uint32_t fileSize;
|
||||
uint32_t chunkSize;
|
||||
uint32_t totalChunks;
|
||||
@@ -25,7 +25,7 @@ struct DownloadState {
|
||||
|
||||
struct UploadState {
|
||||
std::string path;
|
||||
File file;
|
||||
FILE* file;
|
||||
uint32_t fileSize;
|
||||
uint32_t totalChunks;
|
||||
uint32_t chunksReceived;
|
||||
@@ -36,7 +36,6 @@ struct UploadState {
|
||||
std::string errorMessage;
|
||||
};
|
||||
|
||||
// Callback type for sending messages to clients
|
||||
using SendMetadataCallback = std::function<void(const socket_message_FSDownloadMetadata&, int clientId)>;
|
||||
using SendCallback = std::function<void(const socket_message_FSDownloadData&, int clientId)>;
|
||||
using SendCompleteCallback = std::function<void(const socket_message_FSDownloadComplete&, int clientId)>;
|
||||
@@ -46,35 +45,17 @@ class FileSystemHandler {
|
||||
public:
|
||||
FileSystemHandler();
|
||||
|
||||
// Set callbacks for sending streaming data
|
||||
void setSendCallbacks(SendMetadataCallback sendMetadata, SendCallback sendData, SendCompleteCallback sendComplete,
|
||||
SendUploadCompleteCallback sendUploadComplete);
|
||||
|
||||
// Delete file/directory
|
||||
socket_message_FSDeleteResponse handleDelete(const socket_message_FSDeleteRequest& req);
|
||||
|
||||
// Create directory
|
||||
socket_message_FSMkdirResponse handleMkdir(const socket_message_FSMkdirRequest& req);
|
||||
|
||||
// List directory
|
||||
socket_message_FSListResponse handleList(const socket_message_FSListRequest& req);
|
||||
|
||||
// Streaming download - starts the download and streams all chunks
|
||||
void handleDownloadRequest(const socket_message_FSDownloadRequest& req, int clientId);
|
||||
|
||||
// Streaming upload - start upload session
|
||||
socket_message_FSUploadStartResponse handleUploadStart(const socket_message_FSUploadStart& req, int clientId);
|
||||
|
||||
// Streaming upload - receive chunk data (fire-and-forget from client)
|
||||
void handleUploadData(const socket_message_FSUploadData& req);
|
||||
|
||||
// Cancel transfer
|
||||
socket_message_FSCancelTransferResponse handleCancelTransfer(const socket_message_FSCancelTransfer& req);
|
||||
|
||||
// Cleanup expired transfers
|
||||
void cleanupExpiredTransfers();
|
||||
|
||||
// Process pending downloads (call from main loop)
|
||||
void processPendingDownloads();
|
||||
|
||||
private:
|
||||
@@ -91,9 +72,7 @@ class FileSystemHandler {
|
||||
|
||||
void listDirectory(const std::string& path, socket_message_FSListResponse& response);
|
||||
bool deleteRecursive(const std::string& path);
|
||||
|
||||
bool sendNextDownloadChunk(uint32_t transferId);
|
||||
|
||||
void finalizeUpload(uint32_t transferId, bool success, const std::string& error = "");
|
||||
};
|
||||
|
||||
|
||||
+7
-18
@@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp32-hal.h>
|
||||
#include <sdkconfig.h>
|
||||
#include <esp_system.h>
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/rtc.h"
|
||||
#ifndef ESP_PLATFORM_NAME
|
||||
#define ESP_PLATFORM_NAME "ESP32"
|
||||
#endif
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#ifndef ESP_PLATFORM_NAME
|
||||
#define ESP_PLATFORM_NAME "ESP32-S2"
|
||||
#endif
|
||||
@@ -26,24 +27,12 @@
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_VERSION
|
||||
#ifndef STRINGIFY
|
||||
#define STRINGIFY(s) #s
|
||||
#endif
|
||||
#define ARDUINO_VERSION_STR(major, minor, patch) "v" STRINGIFY(major) "." STRINGIFY(minor) "." STRINGIFY(patch)
|
||||
#define ARDUINO_VERSION \
|
||||
ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* I2C software connection
|
||||
*/
|
||||
#ifndef SDA_PIN
|
||||
#define SDA_PIN SDA
|
||||
#define SDA_PIN 21
|
||||
#endif
|
||||
#ifndef SCL_PIN
|
||||
#define SCL_PIN SCL
|
||||
#define SCL_PIN 22
|
||||
#endif
|
||||
#ifndef I2C_FREQUENCY
|
||||
#define I2C_FREQUENCY 100000UL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <mdns.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <kinematics.h>
|
||||
#include <message_types.h>
|
||||
#include <utils/math_utils.h>
|
||||
#include <cstring>
|
||||
|
||||
class MotionState {
|
||||
protected:
|
||||
@@ -26,15 +28,15 @@ class MotionState {
|
||||
}
|
||||
|
||||
void updateFeet(body_state_t& body_state, const float smoothing_factor = default_smoothing_factor) {
|
||||
if (target_body_state.feet != body_state.feet) {
|
||||
if (std::memcmp(target_body_state.feet, body_state.feet, sizeof(body_state.feet)) != 0) {
|
||||
body_state.updateFeet(target_body_state.feet);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void updateImuOffsets(const float new_omega, const float new_psi) {
|
||||
omega_offset = new_omega * RAD_TO_DEG;
|
||||
psi_offset = new_psi * RAD_TO_DEG;
|
||||
omega_offset = RAD_TO_DEG_F(new_omega);
|
||||
psi_offset = RAD_TO_DEG_F(new_psi);
|
||||
}
|
||||
virtual ~MotionState() {}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <features.h>
|
||||
#include <template/stateful_service.h>
|
||||
|
||||
@@ -316,8 +316,7 @@ class MPU6050Driver {
|
||||
i += chunkSize;
|
||||
address += chunkSize;
|
||||
|
||||
if (address == 0 || address >= 256) {
|
||||
address = 0;
|
||||
if (address == 0) {
|
||||
bank++;
|
||||
setMemoryBank(bank);
|
||||
}
|
||||
|
||||
@@ -1,56 +1,105 @@
|
||||
#ifndef LEDService_h
|
||||
#define LEDService_h
|
||||
|
||||
#include <FastLED.h>
|
||||
#include <driver/rmt_tx.h>
|
||||
#include <led_strip.h>
|
||||
#include <led_strip_rmt.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <utils/timing.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#ifndef WS2812_PIN
|
||||
#define WS2812_PIN 12
|
||||
#endif
|
||||
|
||||
#ifndef WS2812_NUM_LEDS
|
||||
#define WS2812_NUM_LEDS 1 + 12
|
||||
#define WS2812_NUM_LEDS 13
|
||||
#endif
|
||||
|
||||
#define COLOR_ORDER GRB
|
||||
#define CHIPSET WS2811
|
||||
|
||||
class LEDService {
|
||||
private:
|
||||
CRGB leds[WS2812_NUM_LEDS];
|
||||
CRGBPalette16 currentPalette;
|
||||
TBlendType currentBlending;
|
||||
|
||||
led_strip_handle_t led_strip = nullptr;
|
||||
int _brightness = 255;
|
||||
int direction = 1;
|
||||
bool initialized = false;
|
||||
|
||||
struct RGB {
|
||||
uint8_t r, g, b;
|
||||
};
|
||||
|
||||
RGB oceanColor = {0, 119, 190};
|
||||
RGB forestColor = {34, 139, 34};
|
||||
|
||||
public:
|
||||
LEDService() {
|
||||
FastLED.addLeds<CHIPSET, WS2812_PIN, COLOR_ORDER>(leds, WS2812_NUM_LEDS).setCorrection(TypicalLEDStrip);
|
||||
currentPalette = OceanColors_p;
|
||||
currentBlending = LINEARBLEND;
|
||||
LEDService() {}
|
||||
|
||||
~LEDService() {
|
||||
if (initialized && led_strip) {
|
||||
led_strip_del(led_strip);
|
||||
}
|
||||
}
|
||||
|
||||
void begin() {
|
||||
if (initialized) return;
|
||||
|
||||
led_strip_config_t strip_config = {
|
||||
.strip_gpio_num = WS2812_PIN,
|
||||
.max_leds = WS2812_NUM_LEDS,
|
||||
.led_pixel_format = LED_PIXEL_FORMAT_GRB,
|
||||
.led_model = LED_MODEL_WS2812,
|
||||
.flags = {.invert_out = false},
|
||||
};
|
||||
|
||||
led_strip_rmt_config_t rmt_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 10 * 1000 * 1000,
|
||||
.mem_block_symbols = 64,
|
||||
.flags = {.with_dma = false},
|
||||
};
|
||||
|
||||
esp_err_t err = led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip);
|
||||
if (err == ESP_OK) {
|
||||
initialized = true;
|
||||
led_strip_clear(led_strip);
|
||||
ESP_LOGI("LEDService", "LED strip initialized on GPIO %d", WS2812_PIN);
|
||||
} else {
|
||||
ESP_LOGE("LEDService", "Failed to initialize LED strip: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
~LEDService() {}
|
||||
|
||||
void loop() {
|
||||
if (!initialized) return;
|
||||
|
||||
EXECUTE_EVERY_N_MS(1000 / 60, {
|
||||
if (_brightness >= 200) direction = -5;
|
||||
if (_brightness <= 50) direction = 5;
|
||||
_brightness += direction;
|
||||
if (WiFi.isConnected()) {
|
||||
fillFromPallette(OceanColors_p, 0);
|
||||
} else {
|
||||
fillFromPallette(ForestColors_p, 128);
|
||||
|
||||
RGB color = WiFi.isConnected() ? oceanColor : forestColor;
|
||||
|
||||
uint8_t r = (color.r * _brightness) / 255;
|
||||
uint8_t g = (color.g * _brightness) / 255;
|
||||
uint8_t b = (color.b * _brightness) / 255;
|
||||
|
||||
for (int i = 0; i < WS2812_NUM_LEDS; ++i) {
|
||||
led_strip_set_pixel(led_strip, i, r, g, b);
|
||||
}
|
||||
FastLED.show();
|
||||
led_strip_refresh(led_strip);
|
||||
});
|
||||
}
|
||||
|
||||
void fillFromPallette(CRGBPalette16 colorPalette, uint8_t colorIndex) {
|
||||
CRGB color = ColorFromPalette(colorPalette, colorIndex, _brightness, currentBlending);
|
||||
void setColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||
if (!initialized) return;
|
||||
for (int i = 0; i < WS2812_NUM_LEDS; ++i) {
|
||||
leds[i] = color;
|
||||
led_strip_set_pixel(led_strip, i, r, g, b);
|
||||
}
|
||||
led_strip_refresh(led_strip);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (!initialized) return;
|
||||
led_strip_clear(led_strip);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#if FT_ENABLED(USE_USS)
|
||||
#include <NewPing.h>
|
||||
#endif
|
||||
#include <peripherals/i2c_bus.h>
|
||||
#include <peripherals/imu.h>
|
||||
#include <peripherals/magnetometer.h>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <wifi/dns_server.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <template/state_result.h>
|
||||
#include <platform_shared/api.pb.h>
|
||||
#include <cstring>
|
||||
|
||||
#include <DNSServer.h>
|
||||
|
||||
#ifndef FACTORY_AP_PROVISION_MODE
|
||||
#define FACTORY_AP_PROVISION_MODE api_APProvisionMode_AP_MODE_DISCONNECTED
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <Arduino.h>
|
||||
#include <template/state_result.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <string>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <template/state_result.h>
|
||||
#include <platform_shared/api.pb.h>
|
||||
#include <cstring>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPmDNS.h>
|
||||
#include <mdns.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <WiFi.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <filesystem.h>
|
||||
#include <global.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
#ifndef FSPersistence_h
|
||||
#define FSPersistence_h
|
||||
|
||||
/**
|
||||
* ESP32 SvelteKit
|
||||
*
|
||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
||||
* https://github.com/theelims/ESP32-sveltekit
|
||||
*
|
||||
* Copyright (C) 2018 - 2023 rjwats
|
||||
* Copyright (C) 2023 theelims
|
||||
* Copyright (C) 2025 runeharlyk
|
||||
*
|
||||
* All Rights Reserved. This software may be modified and distributed under
|
||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||
**/
|
||||
|
||||
#include <FS.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <filesystem.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
|
||||
template <class T>
|
||||
class FSPersistence {
|
||||
@@ -34,25 +21,18 @@ class FSPersistence {
|
||||
}
|
||||
|
||||
void readFromFS() {
|
||||
File settingsFile = _fs->open(_filePath, "r");
|
||||
std::string content = FileSystem::readFile(_filePath);
|
||||
|
||||
if (settingsFile) {
|
||||
if (!content.empty()) {
|
||||
JsonDocument jsonDocument;
|
||||
DeserializationError error = deserializeJson(jsonDocument, settingsFile);
|
||||
DeserializationError error = deserializeJson(jsonDocument, content);
|
||||
if (error == DeserializationError::Ok) {
|
||||
JsonVariant jsonObject = jsonDocument.as<JsonVariant>();
|
||||
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||
settingsFile.close();
|
||||
return;
|
||||
}
|
||||
settingsFile.close();
|
||||
}
|
||||
|
||||
// If we reach here we have not been successful in loading the config
|
||||
// and hard-coded defaults are now applied. The settings are then
|
||||
// written back to the file system so the defaults persist between
|
||||
// resets. This last step is required as in some cases defaults contain
|
||||
// randomly generated values which would otherwise be modified on reset.
|
||||
applyDefaults();
|
||||
writeToFS();
|
||||
}
|
||||
@@ -64,13 +44,10 @@ class FSPersistence {
|
||||
|
||||
mkdirs();
|
||||
|
||||
File file = _fs->open(_filePath, "w");
|
||||
std::string content;
|
||||
serializeJson(jsonDocument, content);
|
||||
|
||||
if (!file) return false;
|
||||
|
||||
serializeJson(jsonDocument, file);
|
||||
file.close();
|
||||
return true;
|
||||
return FileSystem::writeFile(_filePath, content.c_str());
|
||||
}
|
||||
|
||||
void disableUpdateHandler() {
|
||||
@@ -90,26 +67,23 @@ class FSPersistence {
|
||||
JsonStateReader<T> _stateReader;
|
||||
JsonStateUpdater<T> _stateUpdater;
|
||||
StatefulService<T> *_statefulService;
|
||||
FS *_fs {&ESP_FS};
|
||||
const char *_filePath;
|
||||
size_t _bufferSize;
|
||||
HandlerId _updateHandlerId;
|
||||
|
||||
// We assume we have a _filePath with format
|
||||
// "/directory1/directory2/filename" We create a directory for each missing
|
||||
// parent
|
||||
void mkdirs() {
|
||||
std::string path(_filePath);
|
||||
size_t index = 0;
|
||||
while ((index = path.find('/', index + 1)) != std::string::npos) {
|
||||
std::string segment = path.substr(0, index);
|
||||
if (!_fs->exists(segment.c_str())) _fs->mkdir(segment.c_str());
|
||||
struct stat st;
|
||||
if (stat(segment.c_str(), &st) != 0) {
|
||||
FileSystem::mkdirRecursive(segment.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// We assume the updater supplies sensible defaults if an empty object
|
||||
// is supplied, this virtual function allows that to be changed.
|
||||
virtual void applyDefaults() {
|
||||
JsonDocument jsonDocument;
|
||||
JsonVariant jsonObject = jsonDocument.as<JsonVariant>();
|
||||
@@ -117,4 +91,4 @@ class FSPersistence {
|
||||
}
|
||||
};
|
||||
|
||||
#endif // end FSPersistence
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <esp_netif.h>
|
||||
|
||||
class IPAddress {
|
||||
public:
|
||||
IPAddress() : _addr {0, 0, 0, 0} {}
|
||||
|
||||
IPAddress(uint8_t a, uint8_t b, uint8_t c, uint8_t d) : _addr {a, b, c, d} {}
|
||||
|
||||
IPAddress(uint32_t addr) {
|
||||
_addr[0] = addr & 0xFF;
|
||||
_addr[1] = (addr >> 8) & 0xFF;
|
||||
_addr[2] = (addr >> 16) & 0xFF;
|
||||
_addr[3] = (addr >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
IPAddress(const esp_ip4_addr_t& ip4) {
|
||||
_addr[0] = ip4.addr & 0xFF;
|
||||
_addr[1] = (ip4.addr >> 8) & 0xFF;
|
||||
_addr[2] = (ip4.addr >> 16) & 0xFF;
|
||||
_addr[3] = (ip4.addr >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
operator uint32_t() const {
|
||||
return static_cast<uint32_t>(_addr[0]) | (static_cast<uint32_t>(_addr[1]) << 8) |
|
||||
(static_cast<uint32_t>(_addr[2]) << 16) | (static_cast<uint32_t>(_addr[3]) << 24);
|
||||
}
|
||||
|
||||
operator esp_ip4_addr_t() const {
|
||||
esp_ip4_addr_t ip4;
|
||||
ip4.addr = static_cast<uint32_t>(*this);
|
||||
return ip4;
|
||||
}
|
||||
|
||||
bool operator==(const IPAddress& other) const {
|
||||
return _addr[0] == other._addr[0] && _addr[1] == other._addr[1] && _addr[2] == other._addr[2] &&
|
||||
_addr[3] == other._addr[3];
|
||||
}
|
||||
|
||||
bool operator!=(const IPAddress& other) const { return !(*this == other); }
|
||||
|
||||
uint8_t operator[](int index) const { return _addr[index]; }
|
||||
|
||||
uint8_t& operator[](int index) { return _addr[index]; }
|
||||
|
||||
bool fromString(const char* str) {
|
||||
int parts[4];
|
||||
if (sscanf(str, "%d.%d.%d.%d", &parts[0], &parts[1], &parts[2], &parts[3]) != 4) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (parts[i] < 0 || parts[i] > 255) return false;
|
||||
_addr[i] = static_cast<uint8_t>(parts[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d", _addr[0], _addr[1], _addr[2], _addr[3]);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
const char* c_str() const {
|
||||
static char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d", _addr[0], _addr[1], _addr[2], _addr[3]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _addr[4];
|
||||
};
|
||||
@@ -0,0 +1,144 @@
|
||||
#pragma once
|
||||
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netdb.h>
|
||||
#include <esp_log.h>
|
||||
#include <utils/ip_address.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
#define DNS_PORT 53
|
||||
#define DNS_MAX_PACKET_SIZE 512
|
||||
|
||||
class DNSServer {
|
||||
public:
|
||||
DNSServer() : _socket(-1), _running(false), _task(nullptr) {}
|
||||
~DNSServer() { stop(); }
|
||||
|
||||
bool start(uint16_t port, const char* domainName, const IPAddress& resolvedIP) {
|
||||
if (_running) return true;
|
||||
|
||||
_port = port;
|
||||
_resolvedIP = resolvedIP;
|
||||
_domainName = domainName ? domainName : "*";
|
||||
|
||||
_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (_socket < 0) {
|
||||
ESP_LOGE("DNSServer", "Failed to create socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
struct sockaddr_in serverAddr = {};
|
||||
serverAddr.sin_family = AF_INET;
|
||||
serverAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
serverAddr.sin_port = htons(_port);
|
||||
|
||||
if (bind(_socket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
|
||||
ESP_LOGE("DNSServer", "Failed to bind socket");
|
||||
close(_socket);
|
||||
_socket = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
_running = true;
|
||||
xTaskCreate(dnsTask, "dns_server", 4096, this, 3, &_task);
|
||||
|
||||
ESP_LOGI("DNSServer", "Started on port %d, resolving to %s", _port, _resolvedIP.toString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_running = false;
|
||||
if (_task) {
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
_task = nullptr;
|
||||
}
|
||||
if (_socket >= 0) {
|
||||
close(_socket);
|
||||
_socket = -1;
|
||||
}
|
||||
ESP_LOGI("DNSServer", "Stopped");
|
||||
}
|
||||
|
||||
void processNextRequest() {}
|
||||
|
||||
private:
|
||||
static void dnsTask(void* param) {
|
||||
DNSServer* self = static_cast<DNSServer*>(param);
|
||||
self->run();
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
void run() {
|
||||
uint8_t buffer[DNS_MAX_PACKET_SIZE];
|
||||
struct sockaddr_in clientAddr;
|
||||
socklen_t clientAddrLen = sizeof(clientAddr);
|
||||
|
||||
while (_running) {
|
||||
int len = recvfrom(_socket, buffer, DNS_MAX_PACKET_SIZE, 0, (struct sockaddr*)&clientAddr, &clientAddrLen);
|
||||
if (len > 0) {
|
||||
processRequest(buffer, len, &clientAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processRequest(uint8_t* buffer, int len, struct sockaddr_in* clientAddr) {
|
||||
if (len < 12) return;
|
||||
|
||||
uint16_t flags = (buffer[2] << 8) | buffer[3];
|
||||
if ((flags & 0x8000) != 0) return;
|
||||
|
||||
uint8_t response[DNS_MAX_PACKET_SIZE];
|
||||
memcpy(response, buffer, len);
|
||||
|
||||
response[2] = 0x81;
|
||||
response[3] = 0x80;
|
||||
|
||||
response[6] = 0x00;
|
||||
response[7] = 0x01;
|
||||
|
||||
int responseLen = len;
|
||||
|
||||
response[responseLen++] = 0xC0;
|
||||
response[responseLen++] = 0x0C;
|
||||
|
||||
response[responseLen++] = 0x00;
|
||||
response[responseLen++] = 0x01;
|
||||
|
||||
response[responseLen++] = 0x00;
|
||||
response[responseLen++] = 0x01;
|
||||
|
||||
response[responseLen++] = 0x00;
|
||||
response[responseLen++] = 0x00;
|
||||
response[responseLen++] = 0x00;
|
||||
response[responseLen++] = 0x3C;
|
||||
|
||||
response[responseLen++] = 0x00;
|
||||
response[responseLen++] = 0x04;
|
||||
|
||||
uint32_t ip = static_cast<uint32_t>(_resolvedIP);
|
||||
response[responseLen++] = ip & 0xFF;
|
||||
response[responseLen++] = (ip >> 8) & 0xFF;
|
||||
response[responseLen++] = (ip >> 16) & 0xFF;
|
||||
response[responseLen++] = (ip >> 24) & 0xFF;
|
||||
|
||||
sendto(_socket, response, responseLen, 0, (struct sockaddr*)clientAddr, sizeof(*clientAddr));
|
||||
}
|
||||
|
||||
int _socket;
|
||||
uint16_t _port;
|
||||
IPAddress _resolvedIP;
|
||||
std::string _domainName;
|
||||
std::atomic<bool> _running;
|
||||
TaskHandle_t _task;
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_netif.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/event_groups.h>
|
||||
#include <utils/ip_address.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
typedef enum {
|
||||
WL_NO_SHIELD = 255,
|
||||
WL_IDLE_STATUS = 0,
|
||||
WL_NO_SSID_AVAIL = 1,
|
||||
WL_SCAN_COMPLETED = 2,
|
||||
WL_CONNECTED = 3,
|
||||
WL_CONNECT_FAILED = 4,
|
||||
WL_CONNECTION_LOST = 5,
|
||||
WL_DISCONNECTED = 6
|
||||
} wl_status_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_AUTH_OPEN_IDF = 0,
|
||||
WIFI_AUTH_WEP_IDF,
|
||||
WIFI_AUTH_WPA_PSK_IDF,
|
||||
WIFI_AUTH_WPA2_PSK_IDF
|
||||
} wifi_enc_type_t;
|
||||
|
||||
using WiFiEventCb = std::function<void(int32_t event, void* event_data)>;
|
||||
|
||||
struct WiFiEventHandler {
|
||||
int32_t event_id;
|
||||
WiFiEventCb callback;
|
||||
};
|
||||
|
||||
class WiFiClass {
|
||||
public:
|
||||
WiFiClass();
|
||||
~WiFiClass();
|
||||
|
||||
bool init();
|
||||
|
||||
bool mode(wifi_mode_t mode);
|
||||
wifi_mode_t getMode();
|
||||
|
||||
bool begin(const char* ssid, const char* password = nullptr, int32_t channel = 0, const uint8_t* bssid = nullptr);
|
||||
bool disconnect(bool wifiOff = false);
|
||||
bool reconnect();
|
||||
|
||||
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = IPAddress(),
|
||||
IPAddress dns2 = IPAddress());
|
||||
bool setHostname(const char* hostname);
|
||||
const char* getHostname();
|
||||
|
||||
wl_status_t status();
|
||||
bool isConnected();
|
||||
|
||||
IPAddress localIP();
|
||||
IPAddress subnetMask();
|
||||
IPAddress gatewayIP();
|
||||
IPAddress dnsIP(uint8_t dns_no = 0);
|
||||
|
||||
std::string macAddress();
|
||||
std::string SSID();
|
||||
std::string BSSIDstr();
|
||||
int32_t RSSI();
|
||||
uint8_t channel();
|
||||
|
||||
int16_t scanNetworks(bool async = false);
|
||||
int16_t scanComplete();
|
||||
void scanDelete();
|
||||
|
||||
std::string SSID(uint8_t i);
|
||||
int32_t RSSI(uint8_t i);
|
||||
wifi_enc_type_t encryptionType(uint8_t i);
|
||||
std::string BSSIDstr(uint8_t i);
|
||||
int32_t channel(uint8_t i);
|
||||
void getNetworkInfo(uint8_t i, std::string& ssid, uint8_t& encType, int32_t& rssi, uint8_t*& bssid, int32_t& ch);
|
||||
|
||||
bool softAP(const char* ssid, const char* password = nullptr, int channel = 1, bool ssid_hidden = false,
|
||||
int max_connection = 4);
|
||||
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet);
|
||||
bool softAPdisconnect(bool wifiOff = false);
|
||||
IPAddress softAPIP();
|
||||
std::string softAPmacAddress();
|
||||
uint8_t softAPgetStationNum();
|
||||
|
||||
bool setAutoReconnect(bool autoReconnect);
|
||||
bool persistent(bool persistent);
|
||||
bool setTxPower(int8_t power);
|
||||
|
||||
void onEvent(WiFiEventCb callback, int32_t event_id);
|
||||
|
||||
private:
|
||||
static void eventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
|
||||
void dispatchEvent(int32_t event_id, void* event_data);
|
||||
|
||||
esp_netif_t* _sta_netif;
|
||||
esp_netif_t* _ap_netif;
|
||||
bool _initialized;
|
||||
bool _autoReconnect;
|
||||
bool _persistent;
|
||||
wl_status_t _status;
|
||||
wifi_mode_t _mode;
|
||||
|
||||
std::string _hostname;
|
||||
wifi_ap_record_t* _scanResult;
|
||||
uint16_t _scanCount;
|
||||
int16_t _scanStatus;
|
||||
|
||||
std::vector<WiFiEventHandler> _eventHandlers;
|
||||
|
||||
IPAddress _sta_static_ip;
|
||||
IPAddress _sta_static_gw;
|
||||
IPAddress _sta_static_sn;
|
||||
IPAddress _sta_static_dns1;
|
||||
IPAddress _sta_static_dns2;
|
||||
bool _useStaticIp;
|
||||
};
|
||||
|
||||
extern WiFiClass WiFi;
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <WiFi.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
#include <mdns.h>
|
||||
#include <string>
|
||||
|
||||
#include <filesystem.h>
|
||||
@@ -12,11 +12,17 @@
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <settings/wifi_settings.h>
|
||||
|
||||
#define WIFI_EVENT_STA_DISCONNECTED_IDF WIFI_EVENT_STA_DISCONNECTED
|
||||
#define WIFI_EVENT_STA_STOP_IDF WIFI_EVENT_STA_STOP
|
||||
#define IP_EVENT_STA_GOT_IP_IDF 1000
|
||||
|
||||
class WiFiService : public StatefulService<WiFiSettings> {
|
||||
private:
|
||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
static void getNetworks(JsonObject &root);
|
||||
static void getNetworkStatus(JsonObject &root);
|
||||
void onStationModeDisconnected(int32_t event, void *event_data);
|
||||
void onStationModeStop(int32_t event, void *event_data);
|
||||
static void onStationModeGotIP(int32_t event, void *event_data);
|
||||
|
||||
FSPersistencePB<WiFiSettings> _persistence;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user