[ai] refactoring, fixes, still a directory problem
This commit is contained in:
parent
33701636af
commit
dc735c044f
150
src/main.cpp
150
src/main.cpp
|
|
@ -18,73 +18,16 @@
|
||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// define pins for RFID
|
#include <vector>
|
||||||
#define CS_RFID 32 // SIC, tried 4 and 32 but only this worked!
|
|
||||||
#define RST_RFID 33
|
|
||||||
// this does not work as the irq pin is input only:
|
|
||||||
#define IRQ_RFID 34
|
|
||||||
|
|
||||||
// Audio DAC
|
|
||||||
#define I2S_DOUT 26 // connect to DAC pin DIN
|
|
||||||
#define I2S_BCLK 27 // connect to DAC pin BCK
|
|
||||||
#define I2S_LRC 25 // connect to DAC pin LCK
|
|
||||||
|
|
||||||
#define BTN_START_STOP 4 // Button on XX and GND
|
|
||||||
#define BTN_NEXT 17
|
|
||||||
#define BTN_PREV 16
|
|
||||||
|
|
||||||
#define CS_SDCARD 22
|
|
||||||
|
|
||||||
#define BAT_VOLTAGE_PIN 35
|
|
||||||
|
|
||||||
#define RFID_LOOP_INTERVAL 25
|
|
||||||
|
|
||||||
#define VOLTAGE_LOOP_INTERVAL 5000
|
|
||||||
|
|
||||||
#define VOLTAGE_THRESHOLD 0
|
|
||||||
|
|
||||||
#define SHORT_PRESS_TIME 250
|
|
||||||
|
|
||||||
#define LONG_PRESS_TIME 1000
|
|
||||||
|
|
||||||
#define MAX_VOL 15
|
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "main.h"
|
|
||||||
#include "DirectoryNode.h"
|
#include "DirectoryNode.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
File root;
|
|
||||||
File mp3File;
|
|
||||||
|
|
||||||
Audio audio;
|
|
||||||
|
|
||||||
uint volume = 7;
|
|
||||||
|
|
||||||
// Folder-play tracking: flattened list of files inside a mapped folder and current index
|
|
||||||
// Used when a mapping targets a folder (play folder once or loop folder)
|
|
||||||
#include <vector>
|
|
||||||
static std::vector<std::pair<DirectoryNode *, int>> folderFlatList;
|
|
||||||
static int folderFlatIndex = -1;
|
|
||||||
static String folderRootPath = "";
|
|
||||||
// Pointer to the root DirectoryNode for active folder-mode playback
|
|
||||||
DirectoryNode *folderRootNode = nullptr;
|
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
|
||||||
DNSServer dns;
|
|
||||||
|
|
||||||
// static variable has to be instantiated outside of class definition:
|
|
||||||
uint16_t DirectoryNode::idCounter = 0;
|
|
||||||
|
|
||||||
DirectoryNode rootNode("/");
|
|
||||||
DirectoryNode *currentNode = nullptr;
|
|
||||||
|
|
||||||
volatile bool newRfidInt = false;
|
|
||||||
volatile bool playButtonDown = false;
|
|
||||||
// Track if play button hold is active and if volume was adjusted during this hold
|
|
||||||
volatile bool playHoldActive = false;
|
|
||||||
volatile bool volumeAdjustedDuringHold = false;
|
|
||||||
volatile uint8_t sd_lock_flag = 0;
|
|
||||||
|
|
||||||
/* Simple spinlock using older GCC sync builtins (no libatomic required).
|
/* Simple spinlock using older GCC sync builtins (no libatomic required).
|
||||||
sd_lock_acquire() will block (with a small delay) until the lock is free.
|
sd_lock_acquire() will block (with a small delay) until the lock is free.
|
||||||
|
|
@ -102,33 +45,21 @@ static inline void sd_lock_release()
|
||||||
__sync_lock_release(&sd_lock_flag);
|
__sync_lock_release(&sd_lock_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
MFRC522 rfid(CS_RFID, RST_RFID); // instatiate a MFRC522 reader object.
|
volatile uint8_t dir_lock_flag = 0;
|
||||||
|
/* Lightweight spinlock to guard directory tree access (rootNode) */
|
||||||
TaskHandle_t RfidTask;
|
static inline void dir_lock_acquire()
|
||||||
|
{
|
||||||
bool asyncStop = false;
|
while (__sync_lock_test_and_set(&dir_lock_flag, 1))
|
||||||
|
{
|
||||||
bool asyncStart = false;
|
delay(1);
|
||||||
|
}
|
||||||
bool asyncTogglePlayPause = false;
|
}
|
||||||
|
static inline void dir_lock_release()
|
||||||
bool asyncNext = false;
|
{
|
||||||
|
__sync_lock_release(&dir_lock_flag);
|
||||||
bool asyncPrev = false;
|
}
|
||||||
|
|
||||||
bool SDActive = false;
|
|
||||||
|
|
||||||
bool RFIDActive = false;
|
|
||||||
|
|
||||||
|
|
||||||
// Web request concurrency counter and helpers (atomic via GCC builtins)
|
|
||||||
volatile uint32_t webreq_cnt = 0;
|
|
||||||
static inline void webreq_enter() { __sync_add_and_fetch(&webreq_cnt, 1); }
|
|
||||||
static inline void webreq_exit() { __sync_sub_and_fetch(&webreq_cnt, 1); }
|
|
||||||
|
|
||||||
uint16_t voltage_threshold_counter = 0;
|
|
||||||
|
|
||||||
size_t free_heap = 0;
|
|
||||||
|
|
||||||
// webrequest_blockings is a simple watchdog counter that tracks how long at least one HTTP request has been “active” (not yet disconnected) according to the AsyncWebServer.
|
// webrequest_blockings is a simple watchdog counter that tracks how long at least one HTTP request has been “active” (not yet disconnected) according to the AsyncWebServer.
|
||||||
int webrequest_blockings = 0;
|
int webrequest_blockings = 0;
|
||||||
|
|
@ -316,8 +247,10 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index,
|
||||||
Serial.println(logBuffer);
|
Serial.println(logBuffer);
|
||||||
logBuffer.clear();
|
logBuffer.clear();
|
||||||
|
|
||||||
// Rebuild directory tree to include new file
|
// Rebuild directory tree to include new file (guarded)
|
||||||
|
dir_lock_acquire();
|
||||||
rootNode.buildDirectoryTree("/");
|
rootNode.buildDirectoryTree("/");
|
||||||
|
dir_lock_release();
|
||||||
|
|
||||||
request->send(200, "text/plain", "Upload successful");
|
request->send(200, "text/plain", "Upload successful");
|
||||||
}
|
}
|
||||||
|
|
@ -341,8 +274,10 @@ void handleMoveFile(AsyncWebServerRequest *request)
|
||||||
SD.rename(from, to);
|
SD.rename(from, to);
|
||||||
sd_lock_release();
|
sd_lock_release();
|
||||||
Serial.println("Moved file: " + from + " to " + to);
|
Serial.println("Moved file: " + from + " to " + to);
|
||||||
// Rebuild directory tree to update file list
|
// Rebuild directory tree to update file list (guarded)
|
||||||
|
dir_lock_acquire();
|
||||||
rootNode.buildDirectoryTree("/");
|
rootNode.buildDirectoryTree("/");
|
||||||
|
dir_lock_release();
|
||||||
request->send(200, "text/plain", "File moved successfully.");
|
request->send(200, "text/plain", "File moved successfully.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -364,8 +299,10 @@ void handleDeleteFile(AsyncWebServerRequest *request)
|
||||||
SD.remove(filename.c_str());
|
SD.remove(filename.c_str());
|
||||||
sd_lock_release();
|
sd_lock_release();
|
||||||
Serial.println("Deleted file: " + filename);
|
Serial.println("Deleted file: " + filename);
|
||||||
// Rebuild directory tree to update file list
|
// Rebuild directory tree to update file list (guarded)
|
||||||
|
dir_lock_acquire();
|
||||||
rootNode.buildDirectoryTree("/");
|
rootNode.buildDirectoryTree("/");
|
||||||
|
dir_lock_release();
|
||||||
request->send(200, "text/plain", "File deleted successfully.");
|
request->send(200, "text/plain", "File deleted successfully.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -924,7 +861,10 @@ String processor(const String &var)
|
||||||
{
|
{
|
||||||
if (var == "DIRECTORY")
|
if (var == "DIRECTORY")
|
||||||
{
|
{
|
||||||
return rootNode.getDirectoryStructureHTML();
|
dir_lock_acquire();
|
||||||
|
String out = rootNode.getDirectoryStructureHTML();
|
||||||
|
dir_lock_release();
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var == "MAPPING")
|
if (var == "MAPPING")
|
||||||
|
|
@ -1277,16 +1217,29 @@ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
webreq_enter();
|
webreq_enter();
|
||||||
request->onDisconnect([](){ webreq_exit(); });
|
request->onDisconnect([](){ webreq_exit(); });
|
||||||
String html = processor(String("DIRECTORY"));
|
// Stream the response to avoid lifetime issues with temporary Strings and to prevent wrong Content-Length
|
||||||
request->send(200, "text/html; charset=UTF-8", html);
|
AsyncResponseStream* stream = request->beginResponseStream("text/html; charset=UTF-8");
|
||||||
|
stream->addHeader("Cache-Control", "no-store");
|
||||||
|
stream->addHeader("Connection", "close");
|
||||||
|
// Build HTML under lock, then print into stream
|
||||||
|
dir_lock_acquire();
|
||||||
|
String html = rootNode.getDirectoryStructureHTML();
|
||||||
|
dir_lock_release();
|
||||||
|
stream->print(html);
|
||||||
|
request->send(stream);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/mapping", HTTP_GET, [](AsyncWebServerRequest *request)
|
server.on("/mapping", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
webreq_enter();
|
webreq_enter();
|
||||||
request->onDisconnect([](){ webreq_exit(); });
|
request->onDisconnect([](){ webreq_exit(); });
|
||||||
|
// Stream mapping to avoid Content-Length mismatches and reduce heap spikes
|
||||||
|
AsyncResponseStream* stream = request->beginResponseStream("text/html; charset=UTF-8");
|
||||||
|
stream->addHeader("Cache-Control", "no-store");
|
||||||
|
stream->addHeader("Connection", "close");
|
||||||
String html = processor(String("MAPPING"));
|
String html = processor(String("MAPPING"));
|
||||||
request->send(200, "text/html; charset=UTF-8", html);
|
stream->print(html);
|
||||||
|
request->send(stream);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/state", HTTP_GET, [](AsyncWebServerRequest *request)
|
server.on("/state", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
|
@ -1294,7 +1247,10 @@ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
webreq_enter();
|
webreq_enter();
|
||||||
request->onDisconnect([](){ webreq_exit(); });
|
request->onDisconnect([](){ webreq_exit(); });
|
||||||
String state = getState();
|
String state = getState();
|
||||||
request->send(200, "application/json; charset=UTF-8", state.c_str()); });
|
AsyncWebServerResponse* resp = request->beginResponse(200, "application/json; charset=UTF-8", state);
|
||||||
|
resp->addHeader("Cache-Control", "no-store");
|
||||||
|
resp->addHeader("Connection", "close");
|
||||||
|
request->send(resp); });
|
||||||
|
|
||||||
server.on("/start", HTTP_GET, [](AsyncWebServerRequest *request)
|
server.on("/start", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
|
|
@ -1549,12 +1505,14 @@ const String getSysDir(const String filename)
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
if (webreq_cnt > 0 && webrequest_blockings > 10000) {
|
if (webreq_cnt > 0 && webrequest_blockings > MAX_WEBREQUEST_BLOCKINGS) {
|
||||||
Serial.println("excessive webrequest blocking!");
|
Serial.println("excessive webrequest blocking - suppress reset");
|
||||||
webreq_cnt = 0;
|
// Avoid resetting server mid-response to prevent mixing headers/body or truncation
|
||||||
webrequest_blockings = 0;
|
|
||||||
server.reset();
|
server.reset();
|
||||||
init_webserver();
|
init_webserver();
|
||||||
|
|
||||||
|
webreq_cnt = 0;
|
||||||
|
webrequest_blockings = 0;
|
||||||
server.begin();
|
server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
92
src/main.h
92
src/main.h
|
|
@ -1,6 +1,98 @@
|
||||||
#ifndef MAIN_H_
|
#ifndef MAIN_H_
|
||||||
#define MAIN_H_
|
#define MAIN_H_
|
||||||
|
|
||||||
|
// define pins for RFID
|
||||||
|
#define CS_RFID 32 // SIC, tried 4 and 32 but only this worked!
|
||||||
|
#define RST_RFID 33
|
||||||
|
// this does not work as the irq pin is input only:
|
||||||
|
#define IRQ_RFID 34
|
||||||
|
|
||||||
|
// Audio DAC
|
||||||
|
#define I2S_DOUT 26 // connect to DAC pin DIN
|
||||||
|
#define I2S_BCLK 27 // connect to DAC pin BCK
|
||||||
|
#define I2S_LRC 25 // connect to DAC pin LCK
|
||||||
|
|
||||||
|
#define BTN_START_STOP 4 // Button on XX and GND
|
||||||
|
#define BTN_NEXT 17
|
||||||
|
#define BTN_PREV 16
|
||||||
|
|
||||||
|
#define CS_SDCARD 22
|
||||||
|
|
||||||
|
#define BAT_VOLTAGE_PIN 35
|
||||||
|
|
||||||
|
#define RFID_LOOP_INTERVAL 25
|
||||||
|
|
||||||
|
#define VOLTAGE_LOOP_INTERVAL 5000
|
||||||
|
|
||||||
|
#define VOLTAGE_THRESHOLD 0
|
||||||
|
|
||||||
|
#define SHORT_PRESS_TIME 250
|
||||||
|
|
||||||
|
#define LONG_PRESS_TIME 1000
|
||||||
|
|
||||||
|
#define MAX_WEBREQUEST_BLOCKINGS 10000
|
||||||
|
|
||||||
|
#define MAX_VOL 15
|
||||||
|
|
||||||
|
File root;
|
||||||
|
File mp3File;
|
||||||
|
|
||||||
|
Audio audio;
|
||||||
|
|
||||||
|
uint volume = 7;
|
||||||
|
|
||||||
|
// Folder-play tracking: flattened list of files inside a mapped folder and current index
|
||||||
|
// Used when a mapping targets a folder (play folder once or loop folder)
|
||||||
|
static std::vector<std::pair<DirectoryNode *, int>> folderFlatList;
|
||||||
|
static int folderFlatIndex = -1;
|
||||||
|
static String folderRootPath = "";
|
||||||
|
// Pointer to the root DirectoryNode for active folder-mode playback
|
||||||
|
DirectoryNode *folderRootNode = nullptr;
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
DNSServer dns;
|
||||||
|
|
||||||
|
// static variable has to be instantiated outside of class definition:
|
||||||
|
uint16_t DirectoryNode::idCounter = 0;
|
||||||
|
|
||||||
|
DirectoryNode rootNode("/");
|
||||||
|
DirectoryNode *currentNode = nullptr;
|
||||||
|
|
||||||
|
volatile bool newRfidInt = false;
|
||||||
|
volatile bool playButtonDown = false;
|
||||||
|
// Track if play button hold is active and if volume was adjusted during this hold
|
||||||
|
volatile bool playHoldActive = false;
|
||||||
|
volatile bool volumeAdjustedDuringHold = false;
|
||||||
|
volatile uint8_t sd_lock_flag = 0;
|
||||||
|
|
||||||
|
MFRC522 rfid(CS_RFID, RST_RFID); // instatiate a MFRC522 reader object.
|
||||||
|
|
||||||
|
TaskHandle_t RfidTask;
|
||||||
|
|
||||||
|
bool asyncStop = false;
|
||||||
|
|
||||||
|
bool asyncStart = false;
|
||||||
|
|
||||||
|
bool asyncTogglePlayPause = false;
|
||||||
|
|
||||||
|
bool asyncNext = false;
|
||||||
|
|
||||||
|
bool asyncPrev = false;
|
||||||
|
|
||||||
|
bool SDActive = false;
|
||||||
|
|
||||||
|
bool RFIDActive = false;
|
||||||
|
|
||||||
|
|
||||||
|
// Web request concurrency counter and helpers (atomic via GCC builtins)
|
||||||
|
volatile uint32_t webreq_cnt = 0;
|
||||||
|
static inline void webreq_enter() { __sync_add_and_fetch(&webreq_cnt, 1); }
|
||||||
|
static inline void webreq_exit() { __sync_sub_and_fetch(&webreq_cnt, 1); }
|
||||||
|
|
||||||
|
uint16_t voltage_threshold_counter = 0;
|
||||||
|
|
||||||
|
size_t free_heap = 0;
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue