diff --git a/src/DirectoryNode.cpp b/src/DirectoryNode.cpp index a0dd3a8..fcc992a 100644 --- a/src/DirectoryNode.cpp +++ b/src/DirectoryNode.cpp @@ -1,11 +1,11 @@ #include "DirectoryNode.h" - DirectoryNode::DirectoryNode(const String &nodeName) - : name(nodeName), currentPlaying(nullptr) { - id = DirectoryNode::idCounter; - DirectoryNode::idCounter++; - } + : name(nodeName), currentPlaying(nullptr) +{ + id = DirectoryNode::idCounter; + DirectoryNode::idCounter++; +} DirectoryNode::~DirectoryNode() { @@ -15,7 +15,6 @@ DirectoryNode::~DirectoryNode() } } - const uint16_t DirectoryNode::getId() const { return id; @@ -39,8 +38,10 @@ const std::vector &DirectoryNode::getMP3Files() const void DirectoryNode::setCurrentPlaying(const String *mp3File) { currentPlaying = mp3File; - for (int i=0;ii) { + for (int i = 0; i < mp3Files.size(); i++) + { + if (mp3Files[i] == *mp3File && ids.size() > i) + { currentPlayingId = ids[i]; } } @@ -56,7 +57,8 @@ const uint16_t DirectoryNode::getCurrentPlayingId() const return currentPlayingId; } -uint16_t DirectoryNode::getNextId() { +uint16_t DirectoryNode::getNextId() +{ uint16_t next = DirectoryNode::idCounter; DirectoryNode::idCounter++; return next; @@ -70,14 +72,16 @@ void DirectoryNode::addSubdirectory(DirectoryNode *subdirectory) void DirectoryNode::addMP3File(const String &mp3File) { mp3Files.push_back(mp3File); - ids.push_back(getNextId()); + ids.push_back(getNextId()); } -void DirectoryNode::setSecondsPlayed(const uint32_t seconds) { +void DirectoryNode::setSecondsPlayed(const uint32_t seconds) +{ secondsPlayed = seconds; } -uint32_t DirectoryNode::getSecondsPlayed() { +uint32_t DirectoryNode::getSecondsPlayed() +{ return secondsPlayed; } @@ -92,7 +96,7 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath) break; } - if (entry.isDirectory() && entry.name()[0] != '.' && strcmp(entry.name(),sys_dir.c_str())) + if (entry.isDirectory() && entry.name()[0] != '.' && strcmp(entry.name(), sys_dir.c_str())) { DirectoryNode *newNode = new DirectoryNode(entry.name()); subdirectories.push_back(newNode); @@ -153,20 +157,23 @@ DirectoryNode *DirectoryNode::findFirstDirectoryWithMP3s() return nullptr; } -void DirectoryNode::advanceToFirstMP3InThisNode() { - if (mp3Files.size()>0) { +void DirectoryNode::advanceToFirstMP3InThisNode() +{ + if (mp3Files.size() > 0) + { setCurrentPlaying(&mp3Files[0]); } } - -DirectoryNode* DirectoryNode::advanceToMP3(const uint16_t id) { -for (auto subdir : subdirectories) +DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id) +{ + for (auto subdir : subdirectories) { - if (subdir->getId()==id) { + if (subdir->getId() == id) + { subdir->advanceToFirstMP3InThisNode(); return subdir; - } + } // Have each subdirectory advance its song for (size_t i = 0; i < subdir->ids.size(); i++) @@ -179,8 +186,7 @@ for (auto subdir : subdirectories) subdir->currentPlaying = &subdir->mp3Files[i]; subdir->currentPlayingId = id; return subdir; - } - + } } } } @@ -191,14 +197,15 @@ for (auto subdir : subdirectories) return this; } - -DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) { +DirectoryNode *DirectoryNode::advanceToMP3(const String *currentGlobal) +{ for (auto subdir : subdirectories) { - if (subdir->getName()==*currentGlobal) { + if (subdir->getName() == *currentGlobal) + { subdir->advanceToFirstMP3InThisNode(); return subdir; - } + } // Have each subdirectory advance its song for (size_t i = 0; i < subdir->mp3Files.size(); i++) @@ -210,8 +217,7 @@ DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) { { subdir->setCurrentPlaying(&subdir->mp3Files[i]); return subdir; - } - + } } } } @@ -222,7 +228,50 @@ DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) { return this; } -DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal) +/** + * Moves to the previous MP3 file in the directory. + * If the current song has been playing for more than a specific threshold, restarts the current song. + * If the current song has just started, or it's the first song, moves to the previous song in the directory. + * + * @param thresholdSeconds The number of seconds to decide whether to restart the current song or go to the previous song. + * @return A pointer to the DirectoryNode where the new current song is located, or nullptr if there's no previous song. + */ +DirectoryNode *DirectoryNode::goToPreviousMP3(uint32_t thresholdSeconds) +{ + if (secondsPlayed > thresholdSeconds || currentPlaying == nullptr) + { + // Restart the current song if it's been playing for more than thresholdSeconds + // Or if there is no current song (at the start of the list) + return this; + } + else + { + // Find the previous song + for (size_t i = 0; i < mp3Files.size(); i++) + { + if (currentPlaying != nullptr && *currentPlaying == mp3Files[i] && i > 0) + { + // Move to the previous song + setCurrentPlaying(&mp3Files[i - 1]); + return this; + } + } + + // If the first song in the directory or no song was playing, move to the previous directory, if any + for (auto subdir : subdirectories) + { + DirectoryNode *previousNode = subdir->goToPreviousMP3(thresholdSeconds); + if (previousNode != nullptr) + { + return previousNode; + } + } + } + // No previous song available + return nullptr; +} + +DirectoryNode *DirectoryNode::advanceToNextMP3(const String *currentGlobal) { bool useFirst = false; Serial.println(currentGlobal->c_str()); @@ -230,7 +279,7 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal) { for (size_t i = 0; i < mp3Files.size(); i++) { - if (*currentGlobal==mp3Files[i]) + if (*currentGlobal == mp3Files[i]) { // Found the current playing MP3 file if (i < mp3Files.size() - 1) @@ -245,14 +294,14 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal) } } } - // We are either not playing, or we've exhausted all the MP3 files in this directory. // Therefore, we need to recursively look in our subdirectories. for (auto subdir : subdirectories) { - if (useFirst && subdir->mp3Files.size()>0) { + if (useFirst && subdir->mp3Files.size() > 0) + { subdir->setCurrentPlaying(&subdir->mp3Files[0]); return subdir; } @@ -268,7 +317,9 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal) // Advance to the next MP3 file in the same directory subdir->setCurrentPlaying(&subdir->mp3Files[i + 1]); return subdir; - } else { + } + else + { useFirst = true; } // Reached the end of the MP3 files in the directory @@ -287,24 +338,27 @@ String DirectoryNode::getDirectoryStructureHTML() const { String html; html.reserve(1024); // Reserve memory for better performance - if (name=="/") { + if (name == "/") + { html += "\n"; } diff --git a/src/DirectoryNode.h b/src/DirectoryNode.h index 91db6c1..39710a7 100644 --- a/src/DirectoryNode.h +++ b/src/DirectoryNode.h @@ -49,6 +49,7 @@ public: void printDirectoryTree(int level = 0) const; DirectoryNode* advanceToMP3(const String* currentGlobal); DirectoryNode* advanceToNextMP3(const String* currentGlobal); + DirectoryNode* goToPreviousMP3(uint32_t thresholdSeconds = 3); DirectoryNode* advanceToMP3(const uint16_t id); void advanceToFirstMP3InThisNode(); String getDirectoryStructureHTML() const; diff --git a/src/WebContent.h b/src/WebContent.h index ee98487..bbf8908 100644 --- a/src/WebContent.h +++ b/src/WebContent.h @@ -14,7 +14,7 @@ const char index_html[] PROGMEM = R"rawliteral(
- +

diff --git a/src/main.cpp b/src/main.cpp index 4e7a2fc..082f3ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,6 +37,8 @@ #define VOLTAGE_LOOP_INTERVAL 5000 +#define VOLTAGE_THRESHOLD 3800 + #include "globals.h" #include "WebContent.h" #include "css.h" @@ -82,6 +84,8 @@ bool asyncNext = false; bool asyncPrev = false; +uint16_t voltage_threshold_counter = 0; + /* std::map rfid_map{{"67 152 204 14", "01-The_Box_Tops-The_Letter.mp3"}, {"67 175 148 160", "068-Der_Schatz_im_Bergsee"}}; @@ -360,6 +364,37 @@ void next() lastInteraction = millis(); } +void previous() +{ + if (currentNode != nullptr) { + + const String* curr = currentNode->getCurrentPlaying(); + DirectoryNode* newNode = currentNode->goToPreviousMP3(); + + if (newNode != nullptr) { + if (curr == newNode->getCurrentPlaying()) { + // reset to 0 seconds playtime: + audio.setAudioPlayPosition(0); + } else { + // Update the current node and start playing the previous song + Serial.println(""); + Serial.print("Playing previous song: "); + Serial.println(currentNode->getCurrentPlayingFilePath()); + currentNode = newNode; + stop(); + deactivateRFID(); + activateSD(); + playSongByPath(currentNode->getCurrentPlayingFilePath()); + deactivateSD(); + activateRFID(); + } + + + } + } + lastInteraction = millis(); +} + void audio_eof_mp3(const char *info) { Serial.println("audio file ended."); @@ -511,6 +546,12 @@ void setup() request->send(200, "text/plain", "next"); next(); }); + server.on("/previous", HTTP_GET, [](AsyncWebServerRequest *request) + { + + request->send(200, "text/plain", "previous"); + previous(); }); + server.on("/playbyid", HTTP_GET, id_song_action); server.on("/progress", HTTP_POST, progress_action); @@ -663,7 +704,8 @@ void loop() else if (asyncPrev) { asyncPrev = false; - Serial.println("Previous not yet implemented!"); + Serial.println("Previous"); + previous(); } @@ -682,6 +724,18 @@ void loop() if (loopCounter % VOLTAGE_LOOP_INTERVAL == 0) { lastVoltage = getBatteryVoltageMv(); + if (lastVoltage3) { + Serial.println("entering deep sleep due to low voltage..."); + lastInteraction = millis() - sleepMessageDelay; + voltage_threshold_counter = 0; + } else { + voltage_threshold_counter++; + } + } else { + voltage_threshold_counter = 0; + } + } loopCounter++;