hannabox/src/main.h

219 lines
5.2 KiB
C++

#ifndef 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 start();
bool playFile(const char* filename, uint32_t resumeFilePos = 0);
void loop2(void* parameter);
void id_song_action(AsyncWebServerRequest *request);
void progress_action(AsyncWebServerRequest *request);
void volume_action(AsyncWebServerRequest *request);
void init_webserver();
boolean buttonPressed(const uint8_t pin);
const String getSysDir(const String filename);
/**
* Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize)
{
for (byte i = 0; i < bufferSize; i++)
{
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
/* 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_release() releases the lock. This is sufficient for short SD ops. */
static inline void sd_lock_acquire()
{
while (__sync_lock_test_and_set(&sd_lock_flag, 1))
{
delay(1);
}
}
static inline void sd_lock_release()
{
__sync_lock_release(&sd_lock_flag);
}
String getRFIDString(byte uidByte[10])
{
String uidString = String(uidByte[0]) + " " + String(uidByte[1]) + " " +
String(uidByte[2]) + " " + String(uidByte[3]);
return uidString;
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
unsigned long lastStart = 0;
unsigned long lastInteraction = 0;
boolean sleepSoundPlayed = false;
boolean startupSoundPlayed = false;
boolean continuousMode = false;
uint8_t buttontoignore = 0;
uint32_t lastVoltage = 0;
uint loopCounter = 0;
String lastUid = "";
uint16_t currentSongId = 0;
uint32_t currentSongSeconds = 0;
boolean continuePlaying = false;
boolean prepareSleepMode = false;
class DirectoryNode;
/* Mapping entry that stores target (file or folder) and playback mode:
* 's' = single (default) - play only the selected song (or single file in folder)
* 'f' = folder - play files inside the selected folder, then stop
* 'r' = random-folder - play files inside the selected folder in random order, then stop
* 'c' = continuous - continuously play (like previous continuousMode)
*/
struct MappingEntry {
String target;
char mode;
MappingEntry() : target(""), mode('s') {}
MappingEntry(const String& t, char m) : target(t), mode(m) {}
};
std::map<String, MappingEntry> rfid_map;
// Folder-play helper: when a mapping requests "folder only" playback we keep
// track of the folder root node so EOF handling can advance only inside that folder.
bool folderModeActive = false;
bool pendingSeek = false;
uint32_t pendingSeekSeconds = 0;
#endif