From 7a215da0dcb05ab4d0f540efe4421cb2e01885b5 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 15 May 2025 21:48:56 +0200 Subject: [PATCH 01/27] remove audio-tak --- src/AudioPlayer.cpp | 931 +++++++++++++++++++++----------------------- src/AudioPlayer.h | 1 + src/main.cpp | 1 - 3 files changed, 445 insertions(+), 488 deletions(-) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 29d980e4..05ff9e7d 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -46,8 +46,8 @@ static uint8_t AudioPlayer_MinVolume = AUDIOPLAYER_VOLUME_MIN; static uint8_t AudioPlayer_InitVolume = AUDIOPLAYER_VOLUME_INIT; // current playtime -uint32_t AudioPlayer_CurrentTime; -uint32_t AudioPlayer_FileDuration; +uint32_t AudioPlayer_CurrentTime = 0; +uint32_t AudioPlayer_FileDuration = 0; // Playtime stats time_t playTimeSecTotal = 0; @@ -62,7 +62,20 @@ static uint32_t AudioPlayer_HeadphoneLastDetectionTimestamp = 0u; static uint8_t AudioPlayer_MaxVolumeHeadphone = 11u; // Maximum volume that can be adjusted in headphone-mode (default; can be changed later via GUI) #endif -static void AudioPlayer_Task(void *parameter); +Audio audio_class; +Audio *audio = &audio_class; + +// new old varibles +constexpr uint32_t playbackTimeout = 2000; +uint32_t playbackTimeoutStart = millis(); +uint8_t currentVolume; +BaseType_t trackQStatus = pdFAIL; +uint8_t trackCommand = NO_ACTION; +bool audioReturnCode; +uint32_t AudioPlayer_LastPlaytimeStatsTimestamp = 0u; +Playlist *newPlayList = nullptr; +bool newPlayListAvailable = false; + static void AudioPlayer_HeadphoneVolumeManager(void); static std::optional AudioPlayer_ReturnPlaylistFromWebstream(const char *_webUrl); static bool AudioPlayer_ArrSortHelper_strcmp(const char *a, const char *b); @@ -162,18 +175,19 @@ void AudioPlayer_Init(void) { gPlayProperties.dontAcceptRfidTwice = false; } - // Don't start audio-task in BT-speaker mode! - if ((System_GetOperationMode() == OPMODE_NORMAL) || (System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE)) { - xTaskCreatePinnedToCore( - AudioPlayer_Task, /* Function to implement the task */ - "mp3play", /* Name of the task */ - 6000, /* Stack size in words */ - NULL, /* Task input parameter */ - 2 | portPRIVILEGE_BIT, /* Priority of the task */ - &AudioTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ - ); - } +#ifdef I2S_COMM_FMT_LSB_ENABLE + audio->setI2SCommFMT_LSB(true); +#endif + + AudioPlayer_CurrentVolume = AudioPlayer_GetInitVolume(); + audio->setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio->setVolumeSteps(AUDIOPLAYER_VOLUME_MAX); + audio->setVolume(AudioPlayer_CurrentVolume, gPrefsSettings.getUChar("volumeCurve", 0)); + audio->forceMono(gPlayProperties.currentPlayMono); + audio->setTone( + gPrefsSettings.getChar("gainLowPass", 0), + gPrefsSettings.getChar("gainBandPass", 0), + gPrefsSettings.getChar("gainHighPass", 0)); } void AudioPlayer_Exit(void) { @@ -199,6 +213,9 @@ void AudioPlayer_Cyclic(void) { lastPlayingTimestamp = millis(); playTimeSecSinceStart += 1; } + + // Actual loop stuff + AudioPlayer_Loop(); } // Wrapper-function to reverse detection of connected headphones. @@ -374,562 +391,497 @@ void AudioPlayer_HeadphoneVolumeManager(void) { #endif } -class AudioCustom : public Audio { -public: - void *operator new(size_t size) { - return psramFound() ? ps_malloc(size) : malloc(size); - } -}; - // Function to play music as task -void AudioPlayer_Task(void *parameter) { -#ifdef BOARD_HAS_PSRAM - AudioCustom *audio = new AudioCustom(); -#else - static Audio audioAsStatic; // Don't use heap as it's needed for other stuff :-) - Audio *audio = &audioAsStatic; -#endif - -#ifdef I2S_COMM_FMT_LSB_ENABLE - audio->setI2SCommFMT_LSB(true); -#endif +void AudioPlayer_Loop() { + + audio->loop(); + + // Update playtime stats every 250 ms + if ((millis() - AudioPlayer_LastPlaytimeStatsTimestamp) > 250) { + AudioPlayer_LastPlaytimeStatsTimestamp = millis(); + // Update current playtime and duration + AudioPlayer_CurrentTime = audio->getAudioCurrentTime(); + AudioPlayer_FileDuration = audio->getAudioFileDuration(); + // Calculate relative position in file (for trackprogress neopixel & web-ui) + uint32_t fileSize = audio->getFileSize(); + gPlayProperties.audioFileSize = fileSize; + if (!gPlayProperties.playlistFinished && fileSize > 0) { + // for local files and web files with known size + if (!gPlayProperties.pausePlay && (gPlayProperties.seekmode != SEEK_POS_PERCENT)) { // To progress necessary when paused + uint32_t audioDataStartPos = audio->getAudioDataStartPos(); + gPlayProperties.currentRelPos = ((double) (audio->getFilePos() - audioDataStartPos - audio->inBufferFilled()) / (fileSize - audioDataStartPos)) * 100; + } + } else { + if (gPlayProperties.isWebstream && (audio->inBufferSize() > 0)) { + // calc current fillbuffer percent for webstream with unknown size/end + gPlayProperties.currentRelPos = (double) (audio->inBufferFilled() / (double) audio->inBufferSize()) * 100; + } else { + gPlayProperties.currentRelPos = 0; + } + } + } - constexpr uint32_t playbackTimeout = 2000; - uint32_t playbackTimeoutStart = millis(); + if (newPlayListAvailable || gPlayProperties.trackFinished || trackCommand != NO_ACTION) { + if (newPlayListAvailable) { + newPlayListAvailable = false; + audio->stopSong(); - AudioPlayer_CurrentVolume = AudioPlayer_GetInitVolume(); - audio->setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); - audio->setVolumeSteps(AUDIOPLAYER_VOLUME_MAX); - audio->setVolume(AudioPlayer_CurrentVolume, gPrefsSettings.getUChar("volumeCurve", 0)); - audio->forceMono(gPlayProperties.currentPlayMono); - int8_t currentEqualizer[3] = {gPrefsSettings.getChar("gainLowPass", 0), gPrefsSettings.getChar("gainBandPass", 0), gPrefsSettings.getChar("gainHighPass", 0)}; - audio->setTone(currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]); - - uint8_t currentVolume; - BaseType_t trackQStatus = pdFAIL; - uint8_t trackCommand = NO_ACTION; - bool audioReturnCode; - AudioPlayer_CurrentTime = 0; - AudioPlayer_FileDuration = 0; - uint32_t AudioPlayer_LastPlaytimeStatsTimestamp = 0u; - - for (;;) { - /* - if (cnt123++ % 100 == 0) { - Log_Printf(LOGLEVEL_DEBUG, "%u", uxTaskGetStackHighWaterMark(NULL)); - } - */ - if (xQueueReceive(gVolumeQueue, ¤tVolume, 0) == pdPASS) { - Log_Printf(LOGLEVEL_INFO, newLoudnessReceivedQueue, currentVolume); - audio->setVolume(currentVolume, gPrefsSettings.getUChar("volumeCurve", 0)); - Web_SendWebsocketData(0, WebsocketCodeType::Volume); + // destroy the old playlist and assign the new + freePlaylist(gPlayProperties.playlist); + gPlayProperties.playlist = newPlayList; + Log_Printf(LOGLEVEL_NOTICE, newPlaylistReceived, gPlayProperties.playlist->size()); + Log_Printf(LOGLEVEL_DEBUG, "Free heap: %u", ESP.getFreeHeap()); + playbackTimeoutStart = millis(); + gPlayProperties.pausePlay = false; + gPlayProperties.trackFinished = false; + gPlayProperties.playlistFinished = false; #ifdef MQTT_ENABLE - publishMqtt(topicLoudnessState, static_cast(currentVolume), false); + publishMqtt(topicPlaymodeState, static_cast(gPlayProperties.playMode), false); + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); #endif - } - if (xQueueReceive(gEqualizerQueue, ¤tEqualizer, 0) == pdPASS) { - Log_Printf(LOGLEVEL_DEBUG, newEqualizerReceivedQueue, currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]); - audio->setTone(currentEqualizer[0], currentEqualizer[1], currentEqualizer[2]); - } - - if (xQueueReceive(gTrackControlQueue, &trackCommand, 0) == pdPASS) { - Log_Printf(LOGLEVEL_INFO, newCntrlReceivedQueue, trackCommand); + // If we're in audiobook-mode and apply a modification-card, we don't + // want to save lastPlayPosition for the mod-card but for the card that holds the playlist + if (strlen(gCurrentRfidTagId) > 0) { + strncpy(gPlayProperties.playRfidTag, gCurrentRfidTagId, sizeof(gPlayProperties.playRfidTag) / sizeof(gPlayProperties.playRfidTag[0])); + } } - - // Update playtime stats every 250 ms - if ((millis() - AudioPlayer_LastPlaytimeStatsTimestamp) > 250) { - AudioPlayer_LastPlaytimeStatsTimestamp = millis(); - // Update current playtime and duration - AudioPlayer_CurrentTime = audio->getAudioCurrentTime(); - AudioPlayer_FileDuration = audio->getAudioFileDuration(); - // Calculate relative position in file (for trackprogress neopixel & web-ui) - uint32_t fileSize = audio->getFileSize(); - gPlayProperties.audioFileSize = fileSize; - if (!gPlayProperties.playlistFinished && fileSize > 0) { - // for local files and web files with known size - if (!gPlayProperties.pausePlay && (gPlayProperties.seekmode != SEEK_POS_PERCENT)) { // To progress necessary when paused - uint32_t audioDataStartPos = audio->getAudioDataStartPos(); - gPlayProperties.currentRelPos = ((double) (audio->getFilePos() - audioDataStartPos - audio->inBufferFilled()) / (fileSize - audioDataStartPos)) * 100; + if (gPlayProperties.trackFinished) { + gPlayProperties.trackFinished = false; + if (gPlayProperties.playMode == NO_PLAYLIST || gPlayProperties.playlist == nullptr) { + gPlayProperties.playlistFinished = true; + return; + } + if (gPlayProperties.saveLastPlayPosition) { // Don't save for AUDIOBOOK_LOOP because not necessary + if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) { + // Only save if there's another track, otherwise it will be saved at end of playlist anyway + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber + 1, gPlayProperties.playlist->size()); } + } + if (gPlayProperties.sleepAfterCurrentTrack) { // Go to sleep if "sleep after track" was requested + gPlayProperties.playlistFinished = true; + gPlayProperties.playMode = NO_PLAYLIST; + System_RequestSleep(); + return; // TODO-> check if this is necessary or if we need a flag here + } + if (!gPlayProperties.repeatCurrentTrack) { // If endless-loop requested, track-number will not be incremented + gPlayProperties.currentTrackNumber++; } else { - if (gPlayProperties.isWebstream && (audio->inBufferSize() > 0)) { - // calc current fillbuffer percent for webstream with unknown size/end - gPlayProperties.currentRelPos = (double) (audio->inBufferFilled() / (double) audio->inBufferSize()) * 100; - } else { - gPlayProperties.currentRelPos = 0; - } + Log_Println(repeatTrackDueToPlaymode, LOGLEVEL_INFO); + Led_Indicate(LedIndicatorType::Rewind); } } - Playlist *newPlaylist; - trackQStatus = xQueueReceive(gTrackQueue, &newPlaylist, 0); - if (trackQStatus == pdPASS || gPlayProperties.trackFinished || trackCommand != NO_ACTION) { - if (trackQStatus == pdPASS) { + if (gPlayProperties.playlistFinished && trackCommand != NO_ACTION) { + if (gPlayProperties.playMode != BUSY) { // Prevents from staying in mode BUSY forever when error occured (e.g. directory empty that should be played) + Log_Println(noPlaymodeChangeIfIdle, LOGLEVEL_NOTICE); + trackCommand = NO_ACTION; + System_IndicateError(); + return; + } + } + /* Check if track-control was called + (stop, start, next track, prev. track, last track, first track...) */ + switch (trackCommand) { + case STOP: audio->stopSong(); + trackCommand = NO_ACTION; + Log_Println(cmndStop, LOGLEVEL_INFO); + gPlayProperties.pausePlay = true; + gPlayProperties.playlistFinished = true; + gPlayProperties.playMode = NO_PLAYLIST; + Audio_setTitle(noPlaylist); + AudioPlayer_ClearCover(); + return; - // destroy the old playlist and assign the new - freePlaylist(gPlayProperties.playlist); - gPlayProperties.playlist = newPlaylist; - Log_Printf(LOGLEVEL_NOTICE, newPlaylistReceived, gPlayProperties.playlist->size()); - Log_Printf(LOGLEVEL_DEBUG, "Free heap: %u", ESP.getFreeHeap()); - playbackTimeoutStart = millis(); - gPlayProperties.pausePlay = false; - gPlayProperties.trackFinished = false; - gPlayProperties.playlistFinished = false; -#ifdef MQTT_ENABLE - publishMqtt(topicPlaymodeState, static_cast(gPlayProperties.playMode), false); - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); -#endif - - // If we're in audiobook-mode and apply a modification-card, we don't - // want to save lastPlayPosition for the mod-card but for the card that holds the playlist - if (strlen(gCurrentRfidTagId) > 0) { - strncpy(gPlayProperties.playRfidTag, gCurrentRfidTagId, sizeof(gPlayProperties.playRfidTag) / sizeof(gPlayProperties.playRfidTag[0])); - } - } - if (gPlayProperties.trackFinished) { - gPlayProperties.trackFinished = false; - if (gPlayProperties.playMode == NO_PLAYLIST || gPlayProperties.playlist == nullptr) { - gPlayProperties.playlistFinished = true; - continue; - } - if (gPlayProperties.saveLastPlayPosition) { // Don't save for AUDIOBOOK_LOOP because not necessary - if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) { - // Only save if there's another track, otherwise it will be saved at end of playlist anyway - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber + 1, gPlayProperties.playlist->size()); - } - } - if (gPlayProperties.sleepAfterCurrentTrack) { // Go to sleep if "sleep after track" was requested - gPlayProperties.playlistFinished = true; - gPlayProperties.playMode = NO_PLAYLIST; - System_RequestSleep(); - break; - } - if (!gPlayProperties.repeatCurrentTrack) { // If endless-loop requested, track-number will not be incremented - gPlayProperties.currentTrackNumber++; + case PAUSEPLAY: + trackCommand = NO_ACTION; + audio->pauseResume(); + if (gPlayProperties.pausePlay) { + Log_Println(cmndResumeFromPause, LOGLEVEL_INFO); } else { - Log_Println(repeatTrackDueToPlaymode, LOGLEVEL_INFO); - Led_Indicate(LedIndicatorType::Rewind); + Log_Println(cmndPause, LOGLEVEL_INFO); } - } - - if (gPlayProperties.playlistFinished && trackCommand != NO_ACTION) { - if (gPlayProperties.playMode != BUSY) { // Prevents from staying in mode BUSY forever when error occured (e.g. directory empty that should be played) - Log_Println(noPlaymodeChangeIfIdle, LOGLEVEL_NOTICE); - trackCommand = NO_ACTION; - System_IndicateError(); - continue; + if (gPlayProperties.saveLastPlayPosition && !gPlayProperties.pausePlay) { + Log_Printf(LOGLEVEL_INFO, trackPausedAtPos, audio->getFilePos(), audio->getFilePos() - audio->inBufferFilled()); + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), audio->getFilePos() - audio->inBufferFilled(), gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); } - } - /* Check if track-control was called - (stop, start, next track, prev. track, last track, first track...) */ - switch (trackCommand) { - case STOP: - audio->stopSong(); - trackCommand = NO_ACTION; - Log_Println(cmndStop, LOGLEVEL_INFO); - gPlayProperties.pausePlay = true; - gPlayProperties.playlistFinished = true; - gPlayProperties.playMode = NO_PLAYLIST; - Audio_setTitle(noPlaylist); - AudioPlayer_ClearCover(); - continue; + gPlayProperties.pausePlay = !gPlayProperties.pausePlay; + Web_SendWebsocketData(0, WebsocketCodeType::TrackInfo); + return; - case PAUSEPLAY: - trackCommand = NO_ACTION; + case NEXTTRACK: + trackCommand = NO_ACTION; + if (gPlayProperties.pausePlay) { audio->pauseResume(); - if (gPlayProperties.pausePlay) { - Log_Println(cmndResumeFromPause, LOGLEVEL_INFO); + gPlayProperties.pausePlay = false; + } + if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed + gPlayProperties.repeatCurrentTrack = false; +#ifdef MQTT_ENABLE + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); +#endif + } + // Allow next track if current track played in playlist isn't the last track. + // Exception: loop-playlist is active. In this case playback restarts at the first track of the playlist. + if ((gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) || gPlayProperties.repeatPlaylist) { + if ((gPlayProperties.currentTrackNumber + 1 >= gPlayProperties.playlist->size()) && gPlayProperties.repeatPlaylist) { + gPlayProperties.currentTrackNumber = 0; } else { - Log_Println(cmndPause, LOGLEVEL_INFO); + gPlayProperties.currentTrackNumber++; } - if (gPlayProperties.saveLastPlayPosition && !gPlayProperties.pausePlay) { - Log_Printf(LOGLEVEL_INFO, trackPausedAtPos, audio->getFilePos(), audio->getFilePos() - audio->inBufferFilled()); - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), audio->getFilePos() - audio->inBufferFilled(), gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); + if (gPlayProperties.saveLastPlayPosition) { + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); + Log_Println(trackStartAudiobook, LOGLEVEL_INFO); } - gPlayProperties.pausePlay = !gPlayProperties.pausePlay; - Web_SendWebsocketData(0, WebsocketCodeType::TrackInfo); - continue; - - case NEXTTRACK: - trackCommand = NO_ACTION; - if (gPlayProperties.pausePlay) { - audio->pauseResume(); - gPlayProperties.pausePlay = false; + Log_Println(cmndNextTrack, LOGLEVEL_INFO); + if (!gPlayProperties.playlistFinished) { + audio->stopSong(); } - if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed - gPlayProperties.repeatCurrentTrack = false; + } else { + Log_Println(lastTrackAlreadyActive, LOGLEVEL_NOTICE); + System_IndicateError(); + return; + } + break; + + case PREVIOUSTRACK: + trackCommand = NO_ACTION; + if (gPlayProperties.pausePlay) { + audio->pauseResume(); + gPlayProperties.pausePlay = false; + } + if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed + gPlayProperties.repeatCurrentTrack = false; #ifdef MQTT_ENABLE - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); #endif + } + if (gPlayProperties.playMode == WEBSTREAM) { + Log_Println(trackChangeWebstream, LOGLEVEL_INFO); + System_IndicateError(); + return; + } else if (gPlayProperties.playMode == LOCAL_M3U) { + Log_Println(cmndPrevTrack, LOGLEVEL_INFO); + if (gPlayProperties.currentTrackNumber > 0) { + gPlayProperties.currentTrackNumber--; + } else { + System_IndicateError(); + return; } - // Allow next track if current track played in playlist isn't the last track. - // Exception: loop-playlist is active. In this case playback restarts at the first track of the playlist. - if ((gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) || gPlayProperties.repeatPlaylist) { - if ((gPlayProperties.currentTrackNumber + 1 >= gPlayProperties.playlist->size()) && gPlayProperties.repeatPlaylist) { - gPlayProperties.currentTrackNumber = 0; - } else { - gPlayProperties.currentTrackNumber++; + } else { + if (gPlayProperties.currentTrackNumber > 0 || gPlayProperties.repeatPlaylist) { + if (audio->getAudioCurrentTime() < 5) { // play previous track when current track time is small, else play current track again + if (gPlayProperties.currentTrackNumber == 0 && gPlayProperties.repeatPlaylist) { + gPlayProperties.currentTrackNumber = gPlayProperties.playlist->size() - 1; // Go back to last track in loop-mode when first track is played + } else { + gPlayProperties.currentTrackNumber--; + } } + if (gPlayProperties.saveLastPlayPosition) { AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); Log_Println(trackStartAudiobook, LOGLEVEL_INFO); } - Log_Println(cmndNextTrack, LOGLEVEL_INFO); + + Log_Println(cmndPrevTrack, LOGLEVEL_INFO); if (!gPlayProperties.playlistFinished) { audio->stopSong(); } } else { - Log_Println(lastTrackAlreadyActive, LOGLEVEL_NOTICE); - System_IndicateError(); - continue; - } - break; - - case PREVIOUSTRACK: - trackCommand = NO_ACTION; - if (gPlayProperties.pausePlay) { - audio->pauseResume(); - gPlayProperties.pausePlay = false; - } - if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed - gPlayProperties.repeatCurrentTrack = false; -#ifdef MQTT_ENABLE - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); -#endif - } - if (gPlayProperties.playMode == WEBSTREAM) { - Log_Println(trackChangeWebstream, LOGLEVEL_INFO); - System_IndicateError(); - continue; - } else if (gPlayProperties.playMode == LOCAL_M3U) { - Log_Println(cmndPrevTrack, LOGLEVEL_INFO); - if (gPlayProperties.currentTrackNumber > 0) { - gPlayProperties.currentTrackNumber--; - } else { - System_IndicateError(); - continue; + if (gPlayProperties.saveLastPlayPosition) { + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); } - } else { - if (gPlayProperties.currentTrackNumber > 0 || gPlayProperties.repeatPlaylist) { - if (audio->getAudioCurrentTime() < 5) { // play previous track when current track time is small, else play current track again - if (gPlayProperties.currentTrackNumber == 0 && gPlayProperties.repeatPlaylist) { - gPlayProperties.currentTrackNumber = gPlayProperties.playlist->size() - 1; // Go back to last track in loop-mode when first track is played - } else { - gPlayProperties.currentTrackNumber--; - } - } - - if (gPlayProperties.saveLastPlayPosition) { - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); - Log_Println(trackStartAudiobook, LOGLEVEL_INFO); - } - - Log_Println(cmndPrevTrack, LOGLEVEL_INFO); - if (!gPlayProperties.playlistFinished) { - audio->stopSong(); - } - } else { - if (gPlayProperties.saveLastPlayPosition) { - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); - } - audio->stopSong(); - Led_Indicate(LedIndicatorType::Rewind); - audioReturnCode = audio->connecttoFS(gFSystem, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); - // consider track as finished, when audio lib call was not successful - if (!audioReturnCode) { - System_IndicateError(); - gPlayProperties.trackFinished = true; - continue; - } - Log_Println(trackStart, LOGLEVEL_INFO); - continue; + audio->stopSong(); + Led_Indicate(LedIndicatorType::Rewind); + audioReturnCode = audio->connecttoFS(gFSystem, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); + // consider track as finished, when audio lib call was not successful + if (!audioReturnCode) { + System_IndicateError(); + gPlayProperties.trackFinished = true; + return; } + Log_Println(trackStart, LOGLEVEL_INFO); + return; } - break; - case FIRSTTRACK: - trackCommand = NO_ACTION; - if (gPlayProperties.pausePlay) { - audio->pauseResume(); - gPlayProperties.pausePlay = false; - } - gPlayProperties.currentTrackNumber = 0; + } + break; + case FIRSTTRACK: + trackCommand = NO_ACTION; + if (gPlayProperties.pausePlay) { + audio->pauseResume(); + gPlayProperties.pausePlay = false; + } + gPlayProperties.currentTrackNumber = 0; + if (gPlayProperties.saveLastPlayPosition) { + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); + Log_Println(trackStartAudiobook, LOGLEVEL_INFO); + } + Log_Println(cmndFirstTrack, LOGLEVEL_INFO); + if (!gPlayProperties.playlistFinished) { + audio->stopSong(); + } + break; + + case LASTTRACK: + trackCommand = NO_ACTION; + if (gPlayProperties.pausePlay) { + audio->pauseResume(); + gPlayProperties.pausePlay = false; + } + if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) { + gPlayProperties.currentTrackNumber = gPlayProperties.playlist->size() - 1; if (gPlayProperties.saveLastPlayPosition) { AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); Log_Println(trackStartAudiobook, LOGLEVEL_INFO); } - Log_Println(cmndFirstTrack, LOGLEVEL_INFO); + Log_Println(cmndLastTrack, LOGLEVEL_INFO); if (!gPlayProperties.playlistFinished) { audio->stopSong(); } - break; + } else { + Log_Println(lastTrackAlreadyActive, LOGLEVEL_NOTICE); + System_IndicateError(); + return; + } + break; - case LASTTRACK: - trackCommand = NO_ACTION; - if (gPlayProperties.pausePlay) { - audio->pauseResume(); - gPlayProperties.pausePlay = false; - } - if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) { - gPlayProperties.currentTrackNumber = gPlayProperties.playlist->size() - 1; - if (gPlayProperties.saveLastPlayPosition) { - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); - Log_Println(trackStartAudiobook, LOGLEVEL_INFO); - } - Log_Println(cmndLastTrack, LOGLEVEL_INFO); - if (!gPlayProperties.playlistFinished) { - audio->stopSong(); - } - } else { - Log_Println(lastTrackAlreadyActive, LOGLEVEL_NOTICE); - System_IndicateError(); - continue; - } - break; + case 0: + break; - case 0: - break; + default: + trackCommand = NO_ACTION; + Log_Println(cmndDoesNotExist, LOGLEVEL_NOTICE); + System_IndicateError(); + return; + } - default: - trackCommand = NO_ACTION; - Log_Println(cmndDoesNotExist, LOGLEVEL_NOTICE); - System_IndicateError(); - continue; + if (gPlayProperties.playUntilTrackNumber == gPlayProperties.currentTrackNumber && gPlayProperties.playUntilTrackNumber > 0) { + if (gPlayProperties.saveLastPlayPosition) { + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, 0, gPlayProperties.playlist->size()); } + gPlayProperties.playlistFinished = true; + gPlayProperties.playMode = NO_PLAYLIST; + System_RequestSleep(); + return; + } - if (gPlayProperties.playUntilTrackNumber == gPlayProperties.currentTrackNumber && gPlayProperties.playUntilTrackNumber > 0) { + if (gPlayProperties.currentTrackNumber >= gPlayProperties.playlist->size()) { // Check if last element of playlist is already reached + Log_Println(endOfPlaylistReached, LOGLEVEL_NOTICE); + if (!gPlayProperties.repeatPlaylist) { if (gPlayProperties.saveLastPlayPosition) { - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, 0, gPlayProperties.playlist->size()); + // Set back to first track + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(0), 0, gPlayProperties.playMode, 0, gPlayProperties.playlist->size()); } gPlayProperties.playlistFinished = true; gPlayProperties.playMode = NO_PLAYLIST; - System_RequestSleep(); - continue; - } - - if (gPlayProperties.currentTrackNumber >= gPlayProperties.playlist->size()) { // Check if last element of playlist is already reached - Log_Println(endOfPlaylistReached, LOGLEVEL_NOTICE); - if (!gPlayProperties.repeatPlaylist) { - if (gPlayProperties.saveLastPlayPosition) { - // Set back to first track - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(0), 0, gPlayProperties.playMode, 0, gPlayProperties.playlist->size()); - } - gPlayProperties.playlistFinished = true; - gPlayProperties.playMode = NO_PLAYLIST; - Audio_setTitle(noPlaylist); - AudioPlayer_ClearCover(); + Audio_setTitle(noPlaylist); + AudioPlayer_ClearCover(); #ifdef MQTT_ENABLE - publishMqtt(topicPlaymodeState, static_cast(gPlayProperties.playMode), false); + publishMqtt(topicPlaymodeState, static_cast(gPlayProperties.playMode), false); #endif - gPlayProperties.currentTrackNumber = 0; - if (gPlayProperties.sleepAfterPlaylist) { - System_RequestSleep(); - } - continue; - } else { // Check if sleep after current track/playlist was requested - if (gPlayProperties.sleepAfterPlaylist || gPlayProperties.sleepAfterCurrentTrack) { - gPlayProperties.playlistFinished = true; - gPlayProperties.playMode = NO_PLAYLIST; - System_RequestSleep(); - continue; - } // Repeat playlist; set current track number back to 0 - Log_Println(repeatPlaylistDueToPlaymode, LOGLEVEL_NOTICE); - gPlayProperties.currentTrackNumber = 0; - if (gPlayProperties.saveLastPlayPosition) { - AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(0), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); - } + gPlayProperties.currentTrackNumber = 0; + if (gPlayProperties.sleepAfterPlaylist) { + System_RequestSleep(); } - } - - if (!strncmp("http", gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 4)) { - gPlayProperties.isWebstream = true; - } else { - gPlayProperties.isWebstream = false; - } - gPlayProperties.currentRelPos = 0; - audioReturnCode = false; - - if (gPlayProperties.playMode == WEBSTREAM || (gPlayProperties.playMode == LOCAL_M3U && gPlayProperties.isWebstream)) { // Webstream - audioReturnCode = audio->connecttohost(gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); - gPlayProperties.playlistFinished = false; - gTriedToConnectToHost = true; - } else if (gPlayProperties.playMode != WEBSTREAM && !gPlayProperties.isWebstream) { - // Files from SD - if (!gFSystem.exists(gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber))) { // Check first if file/folder exists - Log_Printf(LOGLEVEL_ERROR, dirOrFileDoesNotExist, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); - gPlayProperties.trackFinished = true; - continue; - } else { - audioReturnCode = audio->connecttoFS(gFSystem, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); - // consider track as finished, when audio lib call was not successful + return; + } else { // Check if sleep after current track/playlist was requested + if (gPlayProperties.sleepAfterPlaylist || gPlayProperties.sleepAfterCurrentTrack) { + gPlayProperties.playlistFinished = true; + gPlayProperties.playMode = NO_PLAYLIST; + System_RequestSleep(); + return; + } // Repeat playlist; set current track number back to 0 + Log_Println(repeatPlaylistDueToPlaymode, LOGLEVEL_NOTICE); + gPlayProperties.currentTrackNumber = 0; + if (gPlayProperties.saveLastPlayPosition) { + AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(0), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); } } + } - if (!audioReturnCode) { - System_IndicateError(); + if (!strncmp("http", gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), 4)) { + gPlayProperties.isWebstream = true; + } else { + gPlayProperties.isWebstream = false; + } + gPlayProperties.currentRelPos = 0; + audioReturnCode = false; + + if (gPlayProperties.playMode == WEBSTREAM || (gPlayProperties.playMode == LOCAL_M3U && gPlayProperties.isWebstream)) { // Webstream + audioReturnCode = audio->connecttohost(gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); + gPlayProperties.playlistFinished = false; + gTriedToConnectToHost = true; + } else if (gPlayProperties.playMode != WEBSTREAM && !gPlayProperties.isWebstream) { + // Files from SD + if (!gFSystem.exists(gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber))) { // Check first if file/folder exists + Log_Printf(LOGLEVEL_ERROR, dirOrFileDoesNotExist, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); gPlayProperties.trackFinished = true; - continue; + return; } else { - if (gPlayProperties.currentTrackNumber) { - Led_Indicate(LedIndicatorType::PlaylistProgress); - } - if (gPlayProperties.startAtFilePos > 0) { - audio->setFilePos(gPlayProperties.startAtFilePos); - Log_Printf(LOGLEVEL_NOTICE, trackStartatPos, gPlayProperties.startAtFilePos); - gPlayProperties.startAtFilePos = 0; - } - const char *title = gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber); - if (gPlayProperties.isWebstream) { - title = "Webradio"; - } - if (gPlayProperties.playlist->size() > 1) { - Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber + 1, gPlayProperties.playlist->size(), title); - } else { - Audio_setTitle("%s", title); - } - AudioPlayer_ClearCover(); - Log_Printf(LOGLEVEL_NOTICE, currentlyPlaying, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.playlist->size()); - gPlayProperties.playlistFinished = false; + audioReturnCode = audio->connecttoFS(gFSystem, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber)); + // consider track as finished, when audio lib call was not successful } } - // Handle seekmodes - if (gPlayProperties.seekmode != SEEK_NORMAL) { - if (gPlayProperties.seekmode == SEEK_FORWARDS) { - if (audio->setTimeOffset(jumpOffset)) { - Log_Printf(LOGLEVEL_NOTICE, secondsJumpForward, jumpOffset); - } else { - System_IndicateError(); - } - } else if (gPlayProperties.seekmode == SEEK_BACKWARDS) { - if (audio->setTimeOffset(-(jumpOffset))) { - Log_Printf(LOGLEVEL_NOTICE, secondsJumpBackward, jumpOffset); - } else { - System_IndicateError(); - } - } else if ((gPlayProperties.seekmode == SEEK_POS_PERCENT) && (gPlayProperties.currentRelPos > 0) && (gPlayProperties.currentRelPos < 100)) { - uint32_t newFilePos = uint32_t((double) audio->getAudioDataStartPos() * (1 - gPlayProperties.currentRelPos / 100) + (gPlayProperties.currentRelPos / 100) * audio->getFileSize()); - if (audio->setFilePos(newFilePos)) { - Log_Printf(LOGLEVEL_NOTICE, JumpToPosition, newFilePos, audio->getFileSize()); - } else { - System_IndicateError(); - } + if (!audioReturnCode) { + System_IndicateError(); + gPlayProperties.trackFinished = true; + return; + } else { + if (gPlayProperties.currentTrackNumber) { + Led_Indicate(LedIndicatorType::PlaylistProgress); } - gPlayProperties.seekmode = SEEK_NORMAL; - } - - // Handle IP-announcement - if (gPlayProperties.tellMode == TTS_IP_ADDRESS) { - gPlayProperties.tellMode = TTS_NONE; - String ipText = Wlan_GetIpAddress(); - bool speechOk; - // make IP as text (replace thousand separator with locale text) - switch (LANGUAGE) { - case DE: - ipText.replace(".", "Punkt"); - speechOk = audio->connecttospeech(ipText.c_str(), "de"); - break; - case FR: - ipText.replace(".", "point"); - speechOk = audio->connecttospeech(ipText.c_str(), "fr"); - break; - default: - ipText.replace(".", "point"); - speechOk = audio->connecttospeech(ipText.c_str(), "en"); + if (gPlayProperties.startAtFilePos > 0) { + audio->setFilePos(gPlayProperties.startAtFilePos); + Log_Printf(LOGLEVEL_NOTICE, trackStartatPos, gPlayProperties.startAtFilePos); + gPlayProperties.startAtFilePos = 0; } - if (!speechOk) { - System_IndicateError(); + const char *title = gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber); + if (gPlayProperties.isWebstream) { + title = "Webradio"; } + if (gPlayProperties.playlist->size() > 1) { + Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber + 1, gPlayProperties.playlist->size(), title); + } else { + Audio_setTitle("%s", title); + } + AudioPlayer_ClearCover(); + Log_Printf(LOGLEVEL_NOTICE, currentlyPlaying, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.playlist->size()); + gPlayProperties.playlistFinished = false; } + } - // Handle time-announcement - if (gPlayProperties.tellMode == TTS_CURRENT_TIME) { - gPlayProperties.tellMode = TTS_NONE; - struct tm timeinfo; - getLocalTime(&timeinfo); - static char timeStringBuff[64]; - bool speechOk; -#if (LANGUAGE == DE) - snprintf(timeStringBuff, sizeof(timeStringBuff), "Es ist %02d:%02d Uhr", timeinfo.tm_hour, timeinfo.tm_min); - speechOk = audio->connecttospeech(timeStringBuff, "de"); -#else - if (timeinfo.tm_hour > 12) { - snprintf(timeStringBuff, sizeof(timeStringBuff), "It is %02d:%02d PM", timeinfo.tm_hour - 12, timeinfo.tm_min); + // Handle seekmodes + if (gPlayProperties.seekmode != SEEK_NORMAL) { + if (gPlayProperties.seekmode == SEEK_FORWARDS) { + if (audio->setTimeOffset(jumpOffset)) { + Log_Printf(LOGLEVEL_NOTICE, secondsJumpForward, jumpOffset); } else { - snprintf(timeStringBuff, sizeof(timeStringBuff), "It is %02d:%02d AM", timeinfo.tm_hour, timeinfo.tm_min); + System_IndicateError(); } - speechOk = audio->connecttospeech(timeStringBuff, "en"); -#endif - if (!speechOk) { + } else if (gPlayProperties.seekmode == SEEK_BACKWARDS) { + if (audio->setTimeOffset(-(jumpOffset))) { + Log_Printf(LOGLEVEL_NOTICE, secondsJumpBackward, jumpOffset); + } else { System_IndicateError(); } - } - - // If speech is over, go back to predefined state - if (!gPlayProperties.currentSpeechActive && gPlayProperties.lastSpeechActive) { - gPlayProperties.lastSpeechActive = false; - if (gPlayProperties.playMode != NO_PLAYLIST) { - xQueueSend(gRfidCardQueue, gPlayProperties.playRfidTag, 0); // Re-inject previous RFID-ID in order to continue playback + } else if ((gPlayProperties.seekmode == SEEK_POS_PERCENT) && (gPlayProperties.currentRelPos > 0) && (gPlayProperties.currentRelPos < 100)) { + uint32_t newFilePos = uint32_t((double) audio->getAudioDataStartPos() * (1 - gPlayProperties.currentRelPos / 100) + (gPlayProperties.currentRelPos / 100) * audio->getFileSize()); + if (audio->setFilePos(newFilePos)) { + Log_Printf(LOGLEVEL_NOTICE, JumpToPosition, newFilePos, audio->getFileSize()); + } else { + System_IndicateError(); } } + gPlayProperties.seekmode = SEEK_NORMAL; + } - // Handle if mono/stereo should be changed (e.g. if plugging headphones) - if (gPlayProperties.newPlayMono != gPlayProperties.currentPlayMono) { - gPlayProperties.currentPlayMono = gPlayProperties.newPlayMono; - audio->forceMono(gPlayProperties.currentPlayMono); - if (gPlayProperties.currentPlayMono) { - Log_Println(newPlayModeMono, LOGLEVEL_NOTICE); - } else { - Log_Println(newPlayModeStereo, LOGLEVEL_NOTICE); - } - audio->setTone(gPlayProperties.gainLowPass, gPlayProperties.gainBandPass, gPlayProperties.gainHighPass); + // Handle IP-announcement + if (gPlayProperties.tellMode == TTS_IP_ADDRESS) { + gPlayProperties.tellMode = TTS_NONE; + String ipText = Wlan_GetIpAddress(); + bool speechOk; + // make IP as text (replace thousand separator with locale text) + switch (LANGUAGE) { + case DE: + ipText.replace(".", "Punkt"); + speechOk = audio->connecttospeech(ipText.c_str(), "de"); + break; + case FR: + ipText.replace(".", "point"); + speechOk = audio->connecttospeech(ipText.c_str(), "fr"); + break; + default: + ipText.replace(".", "point"); + speechOk = audio->connecttospeech(ipText.c_str(), "en"); + } + if (!speechOk) { + System_IndicateError(); } + } - audio->loop(); - if (gPlayProperties.playlistFinished || gPlayProperties.pausePlay) { - if (!gPlayProperties.currentSpeechActive) { - vTaskDelay(portTICK_PERIOD_MS * 10); // Waste some time if playlist is not active - } + // Handle time-announcement + if (gPlayProperties.tellMode == TTS_CURRENT_TIME) { + gPlayProperties.tellMode = TTS_NONE; + struct tm timeinfo; + getLocalTime(&timeinfo); + static char timeStringBuff[64]; + bool speechOk; +#if (LANGUAGE == DE) + snprintf(timeStringBuff, sizeof(timeStringBuff), "Es ist %02d:%02d Uhr", timeinfo.tm_hour, timeinfo.tm_min); + speechOk = audio->connecttospeech(timeStringBuff, "de"); +#else + if (timeinfo.tm_hour > 12) { + snprintf(timeStringBuff, sizeof(timeStringBuff), "It is %02d:%02d PM", timeinfo.tm_hour - 12, timeinfo.tm_min); } else { - System_UpdateActivityTimer(); // Refresh if playlist is active so uC will not fall asleep due to reaching inactivity-time + snprintf(timeStringBuff, sizeof(timeStringBuff), "It is %02d:%02d AM", timeinfo.tm_hour, timeinfo.tm_min); } + speechOk = audio->connecttospeech(timeStringBuff, "en"); +#endif + if (!speechOk) { + System_IndicateError(); + } + } - if (audio->isRunning()) { - playbackTimeoutStart = millis(); + // If speech is over, go back to predefined state + if (!gPlayProperties.currentSpeechActive && gPlayProperties.lastSpeechActive) { + gPlayProperties.lastSpeechActive = false; + if (gPlayProperties.playMode != NO_PLAYLIST) { + xQueueSend(gRfidCardQueue, gPlayProperties.playRfidTag, 0); // Re-inject previous RFID-ID in order to continue playback } + } - // If error occured: move to the next track in the playlist - const bool activeMode = (gPlayProperties.playMode != NO_PLAYLIST && gPlayProperties.playMode != BUSY); - const bool noAudio = (!audio->isRunning() && !gPlayProperties.pausePlay); - const bool timeout = ((millis() - playbackTimeoutStart) > playbackTimeout); - if (activeMode) { - // we check for timeout - if (noAudio && timeout) { - // Audio playback timed out, move on to the next - System_IndicateError(); - gPlayProperties.trackFinished = true; - playbackTimeoutStart = millis(); - } + // Handle if mono/stereo should be changed (e.g. if plugging headphones) + if (gPlayProperties.newPlayMono != gPlayProperties.currentPlayMono) { + gPlayProperties.currentPlayMono = gPlayProperties.newPlayMono; + audio->forceMono(gPlayProperties.currentPlayMono); + if (gPlayProperties.currentPlayMono) { + Log_Println(newPlayModeMono, LOGLEVEL_NOTICE); } else { - // we are idle, update timeout so that we do not get a spurious error when launching into a playlist + Log_Println(newPlayModeStereo, LOGLEVEL_NOTICE); + } + audio->setTone(gPlayProperties.gainLowPass, gPlayProperties.gainBandPass, gPlayProperties.gainHighPass); + } + + // audio->loop(); was here before + if (gPlayProperties.playlistFinished || gPlayProperties.pausePlay) { + } else { + System_UpdateActivityTimer(); // Refresh if playlist is active so uC will not fall asleep due to reaching inactivity-time + } + + if (audio->isRunning()) { + playbackTimeoutStart = millis(); + } + + // If error occured: move to the next track in the playlist + const bool activeMode = (gPlayProperties.playMode != NO_PLAYLIST && gPlayProperties.playMode != BUSY); + const bool noAudio = (!audio->isRunning() && !gPlayProperties.pausePlay); + const bool timeout = ((millis() - playbackTimeoutStart) > playbackTimeout); + if (activeMode) { + // we check for timeout + if (noAudio && timeout) { + // Audio playback timed out, move on to the next + System_IndicateError(); + gPlayProperties.trackFinished = true; playbackTimeoutStart = millis(); } - vTaskDelay(portTICK_PERIOD_MS * 1); - - if (gPlayProperties.dontAcceptRfidTwice) { - static uint8_t resetOnNextIdle = false; - if (gPlayProperties.playlistFinished || gPlayProperties.playMode == NO_PLAYLIST) { - if (resetOnNextIdle) { - Rfid_ResetOldRfid(); - resetOnNextIdle = false; - } - } else { - resetOnNextIdle = true; + } else { + // we are idle, update timeout so that we do not get a spurious error when launching into a playlist + playbackTimeoutStart = millis(); + } + + if (gPlayProperties.dontAcceptRfidTwice) { + static uint8_t resetOnNextIdle = false; + if (gPlayProperties.playlistFinished || gPlayProperties.playMode == NO_PLAYLIST) { + if (resetOnNextIdle) { + Rfid_ResetOldRfid(); + resetOnNextIdle = false; } + } else { + resetOnNextIdle = true; } } - vTaskDelete(NULL); } // Returns current repeat-mode (mix of repeat current track and current playlist) @@ -964,15 +916,19 @@ void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRota if (reAdjustRotary) { RotaryEncoder_Readjust(); } - xQueueSend(gVolumeQueue, &_volume, 0); + + audio->setVolume(_volume, gPrefsSettings.getUChar("volumeCurve", 0)); + Web_SendWebsocketData(0, WebsocketCodeType::Volume); +#ifdef MQTT_ENABLE + publishMqtt(topicLoudnessState, static_cast(_volume), false); +#endif AudioPlayer_PauseOnMinVolume(_volumeBuf, _newVolume); } } // Adds equalizer settings low, band and high pass and readjusts the equalizer void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass) { - int8_t _equalizer[3] = {gainLowPass, gainBandPass, gainHighPass}; - xQueueSend(gEqualizerQueue, &_equalizer, 0); + audio->setTone(gainLowPass, gainBandPass, gainHighPass); } // Pauses playback if playback is active and volume is changes from minVolume+1 to minVolume (usually 0) @@ -1159,7 +1115,8 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l if (!error) { gPlayProperties.playMode = _playMode; - xQueueSend(gTrackQueue, &list, 0); + newPlayListAvailable = true; + newPlayList = list; return; } @@ -1230,8 +1187,8 @@ std::optional AudioPlayer_ReturnPlaylistFromWebstream(const char *_w } // Adds new control-command to control-queue -void AudioPlayer_TrackControlToQueueSender(const uint8_t trackCommand) { - xQueueSend(gTrackControlQueue, &trackCommand, 0); +void AudioPlayer_TrackControlToQueueSender(const uint8_t new_trackCommand) { + trackCommand = new_trackCommand; } // Knuth-Fisher-Yates-algorithm to randomize playlist diff --git a/src/AudioPlayer.h b/src/AudioPlayer.h index 7f0b0e24..604b7294 100644 --- a/src/AudioPlayer.h +++ b/src/AudioPlayer.h @@ -56,6 +56,7 @@ extern playProps gPlayProperties; void AudioPlayer_Init(void); void AudioPlayer_Exit(void); void AudioPlayer_Cyclic(void); +void AudioPlayer_Loop(void); uint8_t AudioPlayer_GetRepeatMode(void); void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRotary); void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass); diff --git a/src/main.cpp b/src/main.cpp index 4bca7c2f..7253011d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -235,7 +235,6 @@ void loop() { AudioPlayer_Cyclic(); vTaskDelay(portTICK_PERIOD_MS * 1u); Battery_Cyclic(); - // Port_Cyclic(); // called by button (controlled via hw-timer) Button_Cyclic(); vTaskDelay(portTICK_PERIOD_MS * 1u); System_Cyclic(); From 6a310c7f647d8850fceebb06ef24d5dac1316a97 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 15 May 2025 21:49:17 +0200 Subject: [PATCH 02/27] rename queues and remove queues --- src/AudioPlayer.cpp | 18 +++++++++--------- src/AudioPlayer.h | 8 ++++---- src/Bluetooth.cpp | 13 ++++++------- src/Cmd.cpp | 18 +++++++++--------- src/Mqtt.cpp | 4 ++-- src/Queues.cpp | 23 ----------------------- src/Queues.h | 4 ---- src/RfidCommon.cpp | 2 +- src/RfidMfrc522.cpp | 4 ++-- src/RfidPn5180.cpp | 4 ++-- src/RotaryEncoder.cpp | 2 +- src/Web.cpp | 6 +++--- src/Wlan.cpp | 2 +- 13 files changed, 40 insertions(+), 68 deletions(-) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 05ff9e7d..c14e163b 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -197,7 +197,7 @@ void AudioPlayer_Exit(void) { gPrefsSettings.putULong("playTimeTotal", playTimeSecTotal); // Make sure last playposition for audiobook is saved when playback is active while shutdown was initiated if (gPrefsSettings.getBool("savePosShutdown", false) && !gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + AudioPlayer_SetTrackControl(PAUSEPLAY); while (!gPlayProperties.pausePlay) { // Make sure to wait until playback is paused in order to be sure that playposition saved in NVS vTaskDelay(portTICK_PERIOD_MS * 100u); } @@ -374,7 +374,7 @@ void AudioPlayer_HeadphoneVolumeManager(void) { AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeHeadphone; gPlayProperties.newPlayMono = false; // Always stereo for headphones if (AudioPlayer_GetCurrentVolume() > AudioPlayer_MaxVolume) { - AudioPlayer_VolumeToQueueSender(AudioPlayer_MaxVolume, true); // Lower volume for headphone if headphone's maxvolume is exceeded by volume set in speaker-mode + AudioPlayer_SetVolume(AudioPlayer_MaxVolume, true); // Lower volume for headphone if headphone's maxvolume is exceeded by volume set in speaker-mode } #ifdef GPIO_PA_EN @@ -899,7 +899,7 @@ uint8_t AudioPlayer_GetRepeatMode(void) { // Adds new volume-entry to volume-queue // If volume is changed via webgui or MQTT, it's necessary to re-adjust current value of rotary-encoder. -void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRotary) { +void AudioPlayer_SetVolume(const int32_t _newVolume, bool reAdjustRotary) { uint32_t _volume; int32_t _volumeBuf = AudioPlayer_GetCurrentVolume(); @@ -927,7 +927,7 @@ void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRota } // Adds equalizer settings low, band and high pass and readjusts the equalizer -void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass) { +void AudioPlayer_SetEqualizer(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass) { audio->setTone(gainLowPass, gainBandPass, gainHighPass); } @@ -953,10 +953,10 @@ void AudioPlayer_PauseOnMinVolume(const uint8_t oldVolume, const uint8_t newVolu // Receives de-serialized RFID-data (from NVS) and dispatches playlists for the given // playmode to the track-queue. -void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed) { +void AudioPlayer_SetPlaylist(const char *_itemToPlay, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed) { // Make sure last playposition for audiobook is saved when new RFID-tag is applied if (gPlayProperties.SavePlayPosRfidChange && !gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + AudioPlayer_SetTrackControl(PAUSEPLAY); while (!gPlayProperties.pausePlay) { // Make sure to wait until playback is paused in order to be sure that playposition saved in NVS vTaskDelay(portTICK_PERIOD_MS * 100u); } @@ -988,7 +988,7 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l Log_Println(errorOccured, LOGLEVEL_ERROR); System_IndicateError(); if (gPlayProperties.playMode != NO_PLAYLIST) { - AudioPlayer_TrackControlToQueueSender(STOP); + AudioPlayer_SetTrackControl(STOP); } return; } @@ -999,7 +999,7 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l Log_Println(noMp3FilesInDir, LOGLEVEL_NOTICE); System_IndicateError(); if (!gPlayProperties.pausePlay) { - AudioPlayer_TrackControlToQueueSender(STOP); + AudioPlayer_SetTrackControl(STOP); while (!gPlayProperties.pausePlay) { vTaskDelay(portTICK_PERIOD_MS * 10u); } @@ -1187,7 +1187,7 @@ std::optional AudioPlayer_ReturnPlaylistFromWebstream(const char *_w } // Adds new control-command to control-queue -void AudioPlayer_TrackControlToQueueSender(const uint8_t new_trackCommand) { +void AudioPlayer_SetTrackControl(const uint8_t new_trackCommand) { trackCommand = new_trackCommand; } diff --git a/src/AudioPlayer.h b/src/AudioPlayer.h index 604b7294..ef213619 100644 --- a/src/AudioPlayer.h +++ b/src/AudioPlayer.h @@ -58,10 +58,10 @@ void AudioPlayer_Exit(void); void AudioPlayer_Cyclic(void); void AudioPlayer_Loop(void); uint8_t AudioPlayer_GetRepeatMode(void); -void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRotary); -void AudioPlayer_EqualizerToQueueSender(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass); -void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed); -void AudioPlayer_TrackControlToQueueSender(const uint8_t trackCommand); +void AudioPlayer_SetVolume(const int32_t _newVolume, bool reAdjustRotary); +void AudioPlayer_SetEqualizer(const int8_t gainLowPass, const int8_t gainBandPass, const int8_t gainHighPass); +void AudioPlayer_SetPlaylist(const char *_itemToPlay, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed); +void AudioPlayer_SetTrackControl(const uint8_t trackCommand); void AudioPlayer_PauseOnMinVolume(const uint8_t oldVolume, const uint8_t newVolume); playlistSortMode AudioPlayer_GetPlaylistSortMode(void); diff --git a/src/Bluetooth.cpp b/src/Bluetooth.cpp index 72a87a52..01f5e823 100644 --- a/src/Bluetooth.cpp +++ b/src/Bluetooth.cpp @@ -11,10 +11,10 @@ #include #ifdef BLUETOOTH_ENABLE - #include "esp_bt.h" #include "BluetoothA2DPCommon.h" #include "BluetoothA2DPSink.h" #include "BluetoothA2DPSource.h" + #include "esp_bt.h" #if (defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3)) #include "ESP_I2S.h" I2SClass i2s; @@ -77,17 +77,17 @@ void button_handler(uint8_t id, bool isReleased) { case 68: // 70=pause, 68=resume Log_Printf(LOGLEVEL_DEBUG, "Bluetooth button id %u (pause/resume) is released.", id); - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + AudioPlayer_SetTrackControl(PAUSEPLAY); break; case 75: // 75=next Log_Printf(LOGLEVEL_DEBUG, "Bluetooth button id %u (next track) is released.", id); - AudioPlayer_TrackControlToQueueSender(NEXTTRACK); + AudioPlayer_SetTrackControl(NEXTTRACK); break; case 76: // 76=previous Log_Printf(LOGLEVEL_DEBUG, "Bluetooth button id %u (previous track) is released.", id); - AudioPlayer_TrackControlToQueueSender(PREVIOUSTRACK); + AudioPlayer_SetTrackControl(PREVIOUSTRACK); break; default: // unknown/unsupported button id @@ -201,7 +201,7 @@ void Bluetooth_VolumeChanged(int _newVolume) { _volume = map(_newVolume, 0, 0x7F, BLUETOOTHPLAYER_VOLUME_MIN, BLUETOOTHPLAYER_VOLUME_MAX); if (AudioPlayer_GetCurrentVolume() != _volume) { Log_Printf(LOGLEVEL_INFO, "Bluetooth => volume changed: %d !", _volume); - AudioPlayer_VolumeToQueueSender(_volume, true); + AudioPlayer_SetVolume(_volume, true); } #endif } @@ -227,8 +227,7 @@ void Bluetooth_Init(void) { .bck_io_num = I2S_BCLK, .ws_io_num = I2S_LRC, .data_out_num = I2S_DOUT, - .data_in_num = I2S_PIN_NO_CHANGE - }; + .data_in_num = I2S_PIN_NO_CHANGE}; a2dp_sink->set_pin_config(pin_config); #endif a2dp_sink->set_rssi_callback(rssi); diff --git a/src/Cmd.cpp b/src/Cmd.cpp index b7e46b34..ea3e3df4 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -276,7 +276,7 @@ void Cmd_Action(const uint16_t mod) { case CMD_PLAYPAUSE: { if ((OPMODE_NORMAL == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + AudioPlayer_SetTrackControl(PAUSEPLAY); } else { Bluetooth_PlayPauseTrack(); } @@ -285,7 +285,7 @@ void Cmd_Action(const uint16_t mod) { case CMD_PREVTRACK: { if ((OPMODE_NORMAL == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { - AudioPlayer_TrackControlToQueueSender(PREVIOUSTRACK); + AudioPlayer_SetTrackControl(PREVIOUSTRACK); } else { Bluetooth_PreviousTrack(); } @@ -294,7 +294,7 @@ void Cmd_Action(const uint16_t mod) { case CMD_NEXTTRACK: { if ((OPMODE_NORMAL == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { - AudioPlayer_TrackControlToQueueSender(NEXTTRACK); + AudioPlayer_SetTrackControl(NEXTTRACK); } else { Bluetooth_NextTrack(); } @@ -302,23 +302,23 @@ void Cmd_Action(const uint16_t mod) { } case CMD_FIRSTTRACK: { - AudioPlayer_TrackControlToQueueSender(FIRSTTRACK); + AudioPlayer_SetTrackControl(FIRSTTRACK); break; } case CMD_LASTTRACK: { - AudioPlayer_TrackControlToQueueSender(LASTTRACK); + AudioPlayer_SetTrackControl(LASTTRACK); break; } case CMD_VOLUMEINIT: { - AudioPlayer_VolumeToQueueSender(AudioPlayer_GetInitVolume(), true); + AudioPlayer_SetVolume(AudioPlayer_GetInitVolume(), true); break; } case CMD_VOLUMEUP: { if ((OPMODE_NORMAL == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { - AudioPlayer_VolumeToQueueSender(AudioPlayer_GetCurrentVolume() + 1, true); + AudioPlayer_SetVolume(AudioPlayer_GetCurrentVolume() + 1, true); } else { Bluetooth_SetVolume(AudioPlayer_GetCurrentVolume() + 1, true); } @@ -327,7 +327,7 @@ void Cmd_Action(const uint16_t mod) { case CMD_VOLUMEDOWN: { if ((OPMODE_NORMAL == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { - AudioPlayer_VolumeToQueueSender(AudioPlayer_GetCurrentVolume() - 1, true); + AudioPlayer_SetVolume(AudioPlayer_GetCurrentVolume() - 1, true); } else { Bluetooth_SetVolume(AudioPlayer_GetCurrentVolume() - 1, true); } @@ -364,7 +364,7 @@ void Cmd_Action(const uint16_t mod) { } case CMD_STOP: { - AudioPlayer_TrackControlToQueueSender(STOP); + AudioPlayer_SetTrackControl(STOP); break; } diff --git a/src/Mqtt.cpp b/src/Mqtt.cpp index 9e168558..97c7a09a 100644 --- a/src/Mqtt.cpp +++ b/src/Mqtt.cpp @@ -314,7 +314,7 @@ void Mqtt_ClientCallback(const char *topic_buf, uint32_t topic_length, const cha // Loudness to change? else if (topic_str == topicLoudnessCmnd) { unsigned long vol = toNumber(payload_str); - AudioPlayer_VolumeToQueueSender(vol, true); + AudioPlayer_SetVolume(vol, true); } // Modify sleep-timer? else if (topic_str == topicSleepTimerCmnd) { @@ -380,7 +380,7 @@ void Mqtt_ClientCallback(const char *topic_buf, uint32_t topic_length, const cha // Track-control (pause/play, stop, first, last, next, previous) else if (topic_str == topicTrackControlCmnd) { uint8_t controlCommand = toNumber(payload_str); - AudioPlayer_TrackControlToQueueSender(controlCommand); + AudioPlayer_SetTrackControl(controlCommand); } // Check if controls should be locked diff --git a/src/Queues.cpp b/src/Queues.cpp index 1be5c4e2..14352570 100644 --- a/src/Queues.cpp +++ b/src/Queues.cpp @@ -5,40 +5,17 @@ #include "Playlist.h" #include "Rfid.h" -QueueHandle_t gVolumeQueue; -QueueHandle_t gTrackQueue; -QueueHandle_t gTrackControlQueue; QueueHandle_t gRfidCardQueue; -QueueHandle_t gEqualizerQueue; QueueHandle_t gLedQueue; void Queues_Init(void) { // Create queues - gVolumeQueue = xQueueCreate(1, sizeof(int)); - if (gVolumeQueue == NULL) { - Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Volume"); - } gRfidCardQueue = xQueueCreate(1, cardIdStringSize); if (gRfidCardQueue == NULL) { Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Rfid"); } - gTrackControlQueue = xQueueCreate(1, sizeof(uint8_t)); - if (gTrackControlQueue == NULL) { - Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Track-control"); - } - - gTrackQueue = xQueueCreate(1, sizeof(Playlist *)); - if (gTrackQueue == NULL) { - Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Playlist"); - } - - gEqualizerQueue = xQueueCreate(1, sizeof(int8_t[3])); - if (gEqualizerQueue == NULL) { - Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Equalizer"); - } - gLedQueue = xQueueCreate(1, sizeof(uint8_t)); if (gLedQueue == NULL) { Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Led"); diff --git a/src/Queues.h b/src/Queues.h index 68565f43..c6597621 100644 --- a/src/Queues.h +++ b/src/Queues.h @@ -1,10 +1,6 @@ #pragma once -extern QueueHandle_t gVolumeQueue; -extern QueueHandle_t gTrackQueue; -extern QueueHandle_t gTrackControlQueue; extern QueueHandle_t gRfidCardQueue; -extern QueueHandle_t gEqualizerQueue; extern QueueHandle_t gLedQueue; void Queues_Init(void); diff --git a/src/RfidCommon.cpp b/src/RfidCommon.cpp index d19861c3..6c7efbde 100644 --- a/src/RfidCommon.cpp +++ b/src/RfidCommon.cpp @@ -95,7 +95,7 @@ void Rfid_PreferenceLookupHandler(void) { } #endif - AudioPlayer_TrackQueueDispatcher(_file, _lastPlayPos, _playMode, _trackLastPlayed); + AudioPlayer_SetPlaylist(_file, _lastPlayPos, _playMode, _trackLastPlayed); } } } diff --git a/src/RfidMfrc522.cpp b/src/RfidMfrc522.cpp index b62a57ec..06b54e40 100644 --- a/src/RfidMfrc522.cpp +++ b/src/RfidMfrc522.cpp @@ -131,7 +131,7 @@ void Rfid_Task(void *parameter) { } else { // If pause-button was pressed while card was not applied, playback could be active. If so: don't pause when card is reapplied again as the desired functionality would be reversed in this case. if (gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); // ... play/pause instead (but not for BT) + AudioPlayer_SetTrackControl(PAUSEPLAY); // ... play/pause instead (but not for BT) } } memcpy(lastValidcardId, mfrc522.uid.uidByte, cardIdSize); @@ -170,7 +170,7 @@ void Rfid_Task(void *parameter) { Log_Println(rfidTagRemoved, LOGLEVEL_NOTICE); if (!gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + AudioPlayer_SetTrackControl(PAUSEPLAY); Log_Println(rfidTagReapplied, LOGLEVEL_NOTICE); } mfrc522.PICC_HaltA(); diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index 310527f7..4d53729a 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -225,7 +225,7 @@ void Rfid_Task(void *parameter) { if (gPlayProperties.pauseIfRfidRemoved) { if (!cardAppliedCurrentRun && cardAppliedLastRun && !gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { // Card removed => pause - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + AudioPlayer_SetTrackControl(PAUSEPLAY); Log_Println(rfidTagRemoved, LOGLEVEL_NOTICE); } cardAppliedLastRun = cardAppliedCurrentRun; @@ -283,7 +283,7 @@ void Rfid_Task(void *parameter) { } else { // If pause-button was pressed while card was not applied, playback could be active. If so: don't pause when card is reapplied again as the desired functionality would be reversed in this case. if (gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); // ... play/pause instead + AudioPlayer_SetTrackControl(PAUSEPLAY); // ... play/pause instead Log_Println(rfidTagReapplied, LOGLEVEL_NOTICE); } } diff --git a/src/RotaryEncoder.cpp b/src/RotaryEncoder.cpp index 618ea6db..da6321d6 100644 --- a/src/RotaryEncoder.cpp +++ b/src/RotaryEncoder.cpp @@ -60,7 +60,7 @@ void RotaryEncoder_Cyclic(void) { // just reset the encoder here, so we get a new delta next time encoder.clearCount(); auto currentVol = AudioPlayer_GetCurrentVolume(); - AudioPlayer_VolumeToQueueSender(currentVol + (encoderValue / 2), false); + AudioPlayer_SetVolume(currentVol + (encoderValue / 2), false); return; } #endif diff --git a/src/Web.cpp b/src/Web.cpp index 28907b03..fabb49fa 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -682,7 +682,7 @@ bool JSONToSettings(JsonObject doc) { Log_Printf(LOGLEVEL_ERROR, webSaveSettingsError, "equalizer"); return false; } else { - AudioPlayer_EqualizerToQueueSender(_gainLowPass, _gainBandPass, _gainHighPass); + AudioPlayer_SetEqualizer(_gainLowPass, _gainBandPass, _gainHighPass); } } if (doc["wifi"].is()) { @@ -886,7 +886,7 @@ bool JSONToSettings(JsonObject doc) { const JsonObject controlsObj = doc["controls"].as(); if (controlsObj["set_volume"].is()) { uint8_t new_vol = controlsObj["set_volume"].as(); - AudioPlayer_VolumeToQueueSender(new_vol, true); + AudioPlayer_SetVolume(new_vol, true); } if (controlsObj["action"].is()) { uint8_t cmd = controlsObj["action"].as(); @@ -1926,7 +1926,7 @@ void explorerHandleAudioRequest(AsyncWebServerRequest *request) { if (gPlayProperties.dontAcceptRfidTwice) { Rfid_ResetOldRfid(); } - AudioPlayer_TrackQueueDispatcher(filePath, 0, playMode, 0); + AudioPlayer_SetPlaylist(filePath, 0, playMode, 0); } else { Log_Println("AUDIO: No path variable set", LOGLEVEL_ERROR); } diff --git a/src/Wlan.cpp b/src/Wlan.cpp index 76802121..ce971b4f 100644 --- a/src/Wlan.cpp +++ b/src/Wlan.cpp @@ -777,7 +777,7 @@ void writeWifiStatusToNVS(bool wifiStatus) { } else { Log_Println(wifiDisabledMsg, LOGLEVEL_NOTICE); if (gPlayProperties.isWebstream) { - AudioPlayer_TrackControlToQueueSender(STOP); + AudioPlayer_SetTrackControl(STOP); } } From b683cffe5cbf0cd6a0f810784cdd0be6dda3dc52 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 15 May 2025 22:05:23 +0200 Subject: [PATCH 03/27] place audio into ps-ram again --- src/AudioPlayer.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index c14e163b..d5d8b048 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -62,8 +62,15 @@ static uint32_t AudioPlayer_HeadphoneLastDetectionTimestamp = 0u; static uint8_t AudioPlayer_MaxVolumeHeadphone = 11u; // Maximum volume that can be adjusted in headphone-mode (default; can be changed later via GUI) #endif -Audio audio_class; -Audio *audio = &audio_class; +// dummy class to allocate audio object in PSRAM if available +class AudioCustom : public Audio { +public: + void *operator new(size_t size) { + return psramFound() ? ps_malloc(size) : malloc(size); + } +}; + +Audio *audio = nullptr; // new old varibles constexpr uint32_t playbackTimeout = 2000; @@ -87,6 +94,13 @@ static size_t AudioPlayer_NvsRfidWriteWrapper(const char *_rfidCardId, const cha static void AudioPlayer_ClearCover(void); void AudioPlayer_Init(void) { + // create audio object +#ifdef BOARD_HAS_PSRAM + audio = new AudioCustom(); +#else + static Audio audioAsStatic; // Don't use heap as it's needed for other stuff :-) + audio = &audioAsStatic; +#endif // load playtime total from NVS playTimeSecTotal = gPrefsSettings.getULong("playTimeTotal", 0); From 3e467d1c6555be0bf40b5caca4555835d4a8b2fe Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 15 May 2025 22:24:21 +0200 Subject: [PATCH 04/27] move rfid-task to core 1 --- src/RfidPn5180.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index 4d53729a..a1510291 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -98,7 +98,7 @@ void Rfid_Init(void) { NULL, /* Task input parameter */ 2 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ - 0 /* Core where the task should run */ + 1 /* Core where the task should run */ ); } From ca3531f407362645e2aba05ea005135594aefd99 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 15 May 2025 22:40:09 +0200 Subject: [PATCH 05/27] fix: add log for audio-level again --- src/AudioPlayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index d5d8b048..9cfa5fb5 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -931,6 +931,7 @@ void AudioPlayer_SetVolume(const int32_t _newVolume, bool reAdjustRotary) { RotaryEncoder_Readjust(); } + Log_Printf(LOGLEVEL_INFO, newLoudnessReceivedQueue, currentVolume); audio->setVolume(_volume, gPrefsSettings.getUChar("volumeCurve", 0)); Web_SendWebsocketData(0, WebsocketCodeType::Volume); #ifdef MQTT_ENABLE From 144da010507dd760fc26315682bf2971ef25384e Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Fri, 16 May 2025 08:29:09 +0200 Subject: [PATCH 06/27] some more tweaks on LED and RFID-Task (seems to remove the audio-issues, but not tested yet) --- src/AudioPlayer.cpp | 2 +- src/Bluetooth.cpp | 3 ++- src/Led.cpp | 3 +-- src/Led.h | 6 ++++++ src/RfidMfrc522.cpp | 2 +- src/RfidPn5180.cpp | 4 ++-- src/Web.cpp | 3 --- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 9cfa5fb5..7bd1ba76 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -931,7 +931,7 @@ void AudioPlayer_SetVolume(const int32_t _newVolume, bool reAdjustRotary) { RotaryEncoder_Readjust(); } - Log_Printf(LOGLEVEL_INFO, newLoudnessReceivedQueue, currentVolume); + Log_Printf(LOGLEVEL_INFO, newLoudnessReceivedQueue, _volume); audio->setVolume(_volume, gPrefsSettings.getUChar("volumeCurve", 0)); Web_SendWebsocketData(0, WebsocketCodeType::Volume); #ifdef MQTT_ENABLE diff --git a/src/Bluetooth.cpp b/src/Bluetooth.cpp index 01f5e823..083df4ad 100644 --- a/src/Bluetooth.cpp +++ b/src/Bluetooth.cpp @@ -227,7 +227,8 @@ void Bluetooth_Init(void) { .bck_io_num = I2S_BCLK, .ws_io_num = I2S_LRC, .data_out_num = I2S_DOUT, - .data_in_num = I2S_PIN_NO_CHANGE}; + .data_in_num = I2S_PIN_NO_CHANGE, + }; a2dp_sink->set_pin_config(pin_config); #endif a2dp_sink->set_rssi_callback(rssi); diff --git a/src/Led.cpp b/src/Led.cpp index d71770a1..d44046b9 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -18,8 +18,6 @@ #include #ifdef NEOPIXEL_ENABLE - #include - #define LED_INDICATOR_SET(indicator) ((Led_Indicators) |= (1u << ((uint8_t) indicator))) #define LED_INDICATOR_IS_SET(indicator) (((Led_Indicators) & (1u << ((uint8_t) indicator))) > 0u) #define LED_INDICATOR_CLEAR(indicator) ((Led_Indicators) &= ~(1u << ((uint8_t) indicator))) @@ -359,6 +357,7 @@ static void Led_Task(void *parameter) { FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); FastLED.setBrightness(gLedSettings.Led_Brightness); FastLED.setDither(DISABLE_DITHER); + FastLED.setMaxRefreshRate(120); // limit LED refresh rate to 120Hz (less likely to cause flickering) LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; diff --git a/src/Led.h b/src/Led.h index 07b5dd04..8676f297 100644 --- a/src/Led.h +++ b/src/Led.h @@ -62,6 +62,12 @@ struct AnimationReturnType { #define LED_INITIAL_BRIGHTNESS 16u #define LED_INITIAL_NIGHT_BRIGHTNESS 2u + #define FASTLED_WS2812_T1 350 // original 250 - changed + #define FASTLED_WS2812_T2 700 // original 625 - changed + #define FASTLED_WS2812_T3 150 // original 375 - changed + + #include + struct LedSettings { uint8_t numIndicatorLeds = NUM_INDICATOR_LEDS; uint8_t numControlLeds = NUM_CONTROL_LEDS; diff --git a/src/RfidMfrc522.cpp b/src/RfidMfrc522.cpp index 06b54e40..0b11db7f 100644 --- a/src/RfidMfrc522.cpp +++ b/src/RfidMfrc522.cpp @@ -57,7 +57,7 @@ void Rfid_Init(void) { "rfid", /* Name of the task */ 2048, /* Stack size in words */ NULL, /* Task input parameter */ - 2 | portPRIVILEGE_BIT, /* Priority of the task */ + 1 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ 1 /* Core where the task should run */ ); diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index a1510291..692d5d46 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -94,9 +94,9 @@ void Rfid_Init(void) { xTaskCreatePinnedToCore( Rfid_Task, /* Function to implement the task */ "rfid", /* Name of the task */ - 2176, /* Stack size in words */ + 3072, /* Stack size in words */ NULL, /* Task input parameter */ - 2 | portPRIVILEGE_BIT, /* Priority of the task */ + 1 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ 1 /* Core where the task should run */ ); diff --git a/src/Web.cpp b/src/Web.cpp index fabb49fa..a7f5352a 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -11,9 +11,6 @@ #include "Common.h" #include "ESPAsyncWebServer.h" #include "EnumUtils.h" -#ifdef NEOPIXEL_ENABLE - #include -#endif #include "Ftp.h" #include "HTMLbinary.h" #include "HallEffectSensor.h" From 30ed5767f52b37254007c054e401456247c6f005 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Fri, 16 May 2025 10:58:35 +0200 Subject: [PATCH 07/27] also remove LED-Task --- src/Led.cpp | 406 +++++++++++++++++++++++-------------------------- src/Led.h | 1 + src/Queues.cpp | 6 - src/Queues.h | 1 - src/main.cpp | 7 +- 5 files changed, 198 insertions(+), 223 deletions(-) diff --git a/src/Led.cpp b/src/Led.cpp index d44046b9..c74b4a6a 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -35,8 +35,14 @@ static uint8_t Led_savedBrightness; // global led settings static LedSettings gLedSettings; -TaskHandle_t Led_TaskHandle; -static void Led_Task(void *parameter); +static CRGB *leds = nullptr; +static CRGBSet *indicator = nullptr; +static uint8_t lastLedBrightness = 0; +bool leds_active = false; +bool led_settings_changed = false; +uint8_t numIndicatorLeds = 0; +uint8_t numControlLeds = 0; + static uint8_t Led_Address(uint8_t number); // animation-functions prototypes @@ -139,35 +145,28 @@ bool Led_LoadSettings(LedSettings &settings) { void Led_Init(void) { #ifdef NEOPIXEL_ENABLE - if (Led_TaskHandle) { - // if led task is already running notify to reload settings - uint8_t ledSettingsChanged = 1; - xQueueSend(gLedQueue, &ledSettingsChanged, 0); - return; - } - // load led settings from NVS Led_LoadSettings(gLedSettings); + led_settings_changed = true; - xTaskCreatePinnedToCore( - Led_Task, /* Function to implement the task */ - "Led_Task", /* Name of the task */ - 2048, /* Stack size in words */ - NULL, /* Task input parameter */ - 1, /* Priority of the task */ - &Led_TaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ - ); + lastLedBrightness = gLedSettings.Led_Brightness; + numIndicatorLeds = gLedSettings.numIndicatorLeds; + numControlLeds = gLedSettings.numControlLeds; + // Allocate memory for LED arrays + leds = new CRGB[numIndicatorLeds + numControlLeds]; + indicator = new CRGBSet(leds, numIndicatorLeds); + // initialize FastLED + FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); + FastLED.setBrightness(gLedSettings.Led_Brightness); + FastLED.setDither(DISABLE_DITHER); + FastLED.setMaxRefreshRate(120); // limit LED refresh rate to 120Hz (less likely to cause flickering) + leds_active = true; #endif } void Led_Exit(void) { #ifdef NEOPIXEL_ENABLE Log_Println("shutdown LED..", LOGLEVEL_NOTICE); - if (Led_TaskHandle) { - vTaskDelete(Led_TaskHandle); - Led_TaskHandle = NULL; - } // Turn off LEDs in order to avoid LEDs still glowing when ESP32 is in deepsleep FastLED.clear(true); #endif @@ -343,206 +342,189 @@ bool CheckForPowerButtonAnimation() { #endif #ifdef NEOPIXEL_ENABLE -static void Led_Task(void *parameter) { - static uint8_t lastLedBrightness = gLedSettings.Led_Brightness; - static CRGB *leds = nullptr; - static CRGBSet *indicator = nullptr; - - uint8_t numIndicatorLeds = gLedSettings.numIndicatorLeds; - uint8_t numControlLeds = gLedSettings.numControlLeds; - // Allocate memory for LED arrays - leds = new CRGB[numIndicatorLeds + numControlLeds]; - indicator = new CRGBSet(leds, numIndicatorLeds); - // initialize FastLED - FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); - FastLED.setBrightness(gLedSettings.Led_Brightness); - FastLED.setDither(DISABLE_DITHER); - FastLED.setMaxRefreshRate(120); // limit LED refresh rate to 120Hz (less likely to cause flickering) - - LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; - LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; - bool animationActive = false; - int32_t animationTimer = 0; - uint8_t ledSettingsChanged; - - for (;;) { - - if (xQueueReceive(gLedQueue, &ledSettingsChanged, 0) == pdPASS) { - // load led settings from NVS - Led_LoadSettings(gLedSettings); - // number of indicator/control leds changed - if (((gLedSettings.numIndicatorLeds + gLedSettings.numControlLeds) != (numIndicatorLeds + numControlLeds)) || (gLedSettings.numControlLeds != numControlLeds)) { - FastLED.clear(true); - numIndicatorLeds = gLedSettings.numIndicatorLeds; - numControlLeds = gLedSettings.numControlLeds; - delete (leds); - delete (indicator); - leds = new CRGB[numIndicatorLeds + numControlLeds]; - indicator = new CRGBSet(leds, numIndicatorLeds); - FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); - } - } - - // special handling - if (gLedSettings.Led_Pause) { // Workaround to prevent exceptions while NVS-writes take place - vTaskDelay(portTICK_PERIOD_MS * 10); - continue; - } - - Led_DrawControls(leds); - - uint32_t taskDelay = 20; - bool startNewAnimation = false; - - // check indications and set led-mode - // this mode will then be animated if the priority and the current animation state fit - if (!LED_INDICATOR_IS_SET(LedIndicatorType::BootComplete)) { - nextAnimation = LedAnimationType::Boot; - } else if (CheckForPowerButtonAnimation()) { - nextAnimation = LedAnimationType::Shutdown; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Error)) { - LED_INDICATOR_CLEAR(LedIndicatorType::Error); - nextAnimation = LedAnimationType::Error; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Ok)) { - LED_INDICATOR_CLEAR(LedIndicatorType::Ok); - nextAnimation = LedAnimationType::Ok; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VoltageWarning)) { - LED_INDICATOR_CLEAR(LedIndicatorType::VoltageWarning); - nextAnimation = LedAnimationType::VoltageWarning; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Voltage)) { - nextAnimation = LedAnimationType::BatteryMeasurement; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VolumeChange)) { - nextAnimation = LedAnimationType::Volume; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Rewind)) { - LED_INDICATOR_CLEAR(LedIndicatorType::Rewind); - nextAnimation = LedAnimationType::Rewind; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::PlaylistProgress)) { - nextAnimation = LedAnimationType::Playlist; - } else if (gPlayProperties.currentSpeechActive) { - nextAnimation = LedAnimationType::Speech; - } else if (gPlayProperties.playlistFinished) { - nextAnimation = LedAnimationType::Idle; - } else if (gPlayProperties.pausePlay && !gPlayProperties.isWebstream) { - nextAnimation = LedAnimationType::Pause; - } else if ((gPlayProperties.playMode != BUSY) && (gPlayProperties.playMode != NO_PLAYLIST) && gPlayProperties.audioFileSize > 0) { // progress for a file/stream with known size - nextAnimation = LedAnimationType::Progress; - } else if (gPlayProperties.isWebstream) { // webstream animation (for streams with unknown size); pause animation is also handled by the webstream animation function - nextAnimation = LedAnimationType::Webstream; - } else if (gPlayProperties.playMode == NO_PLAYLIST) { - nextAnimation = LedAnimationType::Idle; - } else if (gPlayProperties.playMode == BUSY) { - nextAnimation = LedAnimationType::Busy; - } else { - nextAnimation = LedAnimationType::NoNewAnimation; // should not happen - } +void Led_Cyclic(void) { + static LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; + static LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; + static bool animationActive = false; + static int32_t animationTimer = 0; + static uint32_t animationStartTimestamp = 0; - // check for instant transition if the requested animation has a higher priority then the current one - if (nextAnimation < activeAnimation) { - animationActive = false; // abort current animation - animationTimer = 0; - } - // transition to new animation - if ((!animationActive) && (animationTimer <= 0)) { - activeAnimation = nextAnimation; // set new animation - startNewAnimation = true; - } + // directly return if no LEDs are active + if (!leds_active) { + return; + } - // apply brightness-changes - if (lastLedBrightness != gLedSettings.Led_Brightness) { - FastLED.setBrightness(gLedSettings.Led_Brightness); - lastLedBrightness = gLedSettings.Led_Brightness; + if (led_settings_changed) { + led_settings_changed = false; + // load led settings from NVS + Led_LoadSettings(gLedSettings); + // number of indicator/control leds changed + if (((gLedSettings.numIndicatorLeds + gLedSettings.numControlLeds) != (numIndicatorLeds + numControlLeds)) || (gLedSettings.numControlLeds != numControlLeds)) { + FastLED.clear(true); + numIndicatorLeds = gLedSettings.numIndicatorLeds; + numControlLeds = gLedSettings.numControlLeds; + delete (leds); + delete (indicator); + leds = new CRGB[numIndicatorLeds + numControlLeds]; + indicator = new CRGBSet(leds, numIndicatorLeds); + FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); } + } - // when there is no delay anymore we have to animate something - if (animationTimer <= 0) { - AnimationReturnType ret; - // animate the current animation - switch (activeAnimation) { - case LedAnimationType::Boot: - ret = Animation_Boot(startNewAnimation, *indicator); - break; - - case LedAnimationType::Shutdown: - ret = Animation_Shutdown(startNewAnimation, *indicator); - break; - - case LedAnimationType::Error: - ret = Animation_Error(startNewAnimation, *indicator); - break; - - case LedAnimationType::Ok: - ret = Animation_Ok(startNewAnimation, *indicator); - break; - - case LedAnimationType::Volume: - ret = Animation_Volume(startNewAnimation, *indicator); - break; - - case LedAnimationType::VoltageWarning: - ret = Animation_VoltageWarning(startNewAnimation, *indicator); - break; - - case LedAnimationType::BatteryMeasurement: - ret = Animation_BatteryMeasurement(startNewAnimation, *indicator); - break; - - case LedAnimationType::Rewind: - ret = Animation_Rewind(startNewAnimation, *indicator); - break; - - case LedAnimationType::Playlist: - ret = Animation_PlaylistProgress(startNewAnimation, *indicator); - break; - - case LedAnimationType::Idle: - ret = Animation_Idle(startNewAnimation, *indicator); - break; - - case LedAnimationType::Busy: - ret = Animation_Busy(startNewAnimation, *indicator); - break; - - case LedAnimationType::Speech: - ret = Animation_Speech(startNewAnimation, *indicator); - break; + // special handling + if (gLedSettings.Led_Pause) { // Workaround to prevent exceptions while NVS-writes take place + return; + } - case LedAnimationType::Pause: - ret = Animation_Pause(startNewAnimation, *indicator); - break; + Led_DrawControls(leds); + + bool startNewAnimation = false; + + // check indications and set led-mode + // this mode will then be animated if the priority and the current animation state fit + if (!LED_INDICATOR_IS_SET(LedIndicatorType::BootComplete)) { + nextAnimation = LedAnimationType::Boot; + } else if (CheckForPowerButtonAnimation()) { + nextAnimation = LedAnimationType::Shutdown; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Error)) { + LED_INDICATOR_CLEAR(LedIndicatorType::Error); + nextAnimation = LedAnimationType::Error; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Ok)) { + LED_INDICATOR_CLEAR(LedIndicatorType::Ok); + nextAnimation = LedAnimationType::Ok; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VoltageWarning)) { + LED_INDICATOR_CLEAR(LedIndicatorType::VoltageWarning); + nextAnimation = LedAnimationType::VoltageWarning; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Voltage)) { + nextAnimation = LedAnimationType::BatteryMeasurement; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VolumeChange)) { + nextAnimation = LedAnimationType::Volume; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Rewind)) { + LED_INDICATOR_CLEAR(LedIndicatorType::Rewind); + nextAnimation = LedAnimationType::Rewind; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::PlaylistProgress)) { + nextAnimation = LedAnimationType::Playlist; + } else if (gPlayProperties.currentSpeechActive) { + nextAnimation = LedAnimationType::Speech; + } else if (gPlayProperties.playlistFinished) { + nextAnimation = LedAnimationType::Idle; + } else if (gPlayProperties.pausePlay && !gPlayProperties.isWebstream) { + nextAnimation = LedAnimationType::Pause; + } else if ((gPlayProperties.playMode != BUSY) && (gPlayProperties.playMode != NO_PLAYLIST) && gPlayProperties.audioFileSize > 0) { // progress for a file/stream with known size + nextAnimation = LedAnimationType::Progress; + } else if (gPlayProperties.isWebstream) { // webstream animation (for streams with unknown size); pause animation is also handled by the webstream animation function + nextAnimation = LedAnimationType::Webstream; + } else if (gPlayProperties.playMode == NO_PLAYLIST) { + nextAnimation = LedAnimationType::Idle; + } else if (gPlayProperties.playMode == BUSY) { + nextAnimation = LedAnimationType::Busy; + } else { + nextAnimation = LedAnimationType::NoNewAnimation; // should not happen + } - case LedAnimationType::Progress: - ret = Animation_Progress(startNewAnimation, *indicator); - break; + // check for instant transition if the requested animation has a higher priority then the current one + if (nextAnimation < activeAnimation) { + animationActive = false; // abort current animation + animationTimer = 0; + } + // transition to new animation + if ((!animationActive) && (animationTimer <= 0)) { + activeAnimation = nextAnimation; // set new animation + startNewAnimation = true; + } - case LedAnimationType::Webstream: - ret = Animation_Webstream(startNewAnimation, *indicator); - break; + // apply brightness-changes + if (lastLedBrightness != gLedSettings.Led_Brightness) { + FastLED.setBrightness(gLedSettings.Led_Brightness); + lastLedBrightness = gLedSettings.Led_Brightness; + } - default: - *indicator = CRGB::Black; - FastLED.show(); - ret.animationActive = false; - ret.animationDelay = 50; - break; - } - // apply delay and state from animation - animationActive = ret.animationActive; - animationTimer = ret.animationDelay; - if (ret.animationRefresh) { + // when there is no delay anymore we have to animate something + if (animationTimer <= 0) { + AnimationReturnType ret; + // animate the current animation + switch (activeAnimation) { + case LedAnimationType::Boot: + ret = Animation_Boot(startNewAnimation, *indicator); + break; + + case LedAnimationType::Shutdown: + ret = Animation_Shutdown(startNewAnimation, *indicator); + break; + + case LedAnimationType::Error: + ret = Animation_Error(startNewAnimation, *indicator); + break; + + case LedAnimationType::Ok: + ret = Animation_Ok(startNewAnimation, *indicator); + break; + + case LedAnimationType::Volume: + ret = Animation_Volume(startNewAnimation, *indicator); + break; + + case LedAnimationType::VoltageWarning: + ret = Animation_VoltageWarning(startNewAnimation, *indicator); + break; + + case LedAnimationType::BatteryMeasurement: + ret = Animation_BatteryMeasurement(startNewAnimation, *indicator); + break; + + case LedAnimationType::Rewind: + ret = Animation_Rewind(startNewAnimation, *indicator); + break; + + case LedAnimationType::Playlist: + ret = Animation_PlaylistProgress(startNewAnimation, *indicator); + break; + + case LedAnimationType::Idle: + ret = Animation_Idle(startNewAnimation, *indicator); + break; + + case LedAnimationType::Busy: + ret = Animation_Busy(startNewAnimation, *indicator); + break; + + case LedAnimationType::Speech: + ret = Animation_Speech(startNewAnimation, *indicator); + break; + + case LedAnimationType::Pause: + ret = Animation_Pause(startNewAnimation, *indicator); + break; + + case LedAnimationType::Progress: + ret = Animation_Progress(startNewAnimation, *indicator); + break; + + case LedAnimationType::Webstream: + ret = Animation_Webstream(startNewAnimation, *indicator); + break; + + default: + *indicator = CRGB::Black; FastLED.show(); - } + ret.animationActive = false; + ret.animationDelay = 50; + break; } - - // get the time to wait and delay the task - if ((animationTimer > 0) && (animationTimer < taskDelay)) { - taskDelay = animationTimer; + // apply delay and state from animation + animationActive = ret.animationActive; + animationTimer = ret.animationDelay; + animationStartTimestamp = millis(); + if (ret.animationRefresh) { + FastLED.show(); } - animationTimer -= taskDelay; - vTaskDelay(portTICK_PERIOD_MS * taskDelay); } - delete (leds); - delete (indicator); - vTaskDelete(NULL); + + // don't do anything else, until time is up + if (((millis() - animationStartTimestamp) >= animationTimer)) { + // we have to wait for the next animation + animationTimer = 0; + } } #endif @@ -1233,13 +1215,13 @@ AnimationReturnType Animation_BatteryMeasurement(const bool startNewAnimation, C void Led_TaskPause(void) { #ifdef NEOPIXEL_ENABLE - vTaskSuspend(Led_TaskHandle); + leds_active = false; FastLED.clear(true); #endif } void Led_TaskResume(void) { #ifdef NEOPIXEL_ENABLE - vTaskResume(Led_TaskHandle); + leds_active = true; #endif } diff --git a/src/Led.h b/src/Led.h index 8676f297..ee6711eb 100644 --- a/src/Led.h +++ b/src/Led.h @@ -97,6 +97,7 @@ uint8_t Led_GetBrightness(void); void Led_SetBrightness(uint8_t value); void Led_TaskPause(void); void Led_TaskResume(void); +void Led_Cyclic(void); void Led_SetNightmode(bool enabled); bool Led_GetNightmode(); diff --git a/src/Queues.cpp b/src/Queues.cpp index 14352570..33cdada9 100644 --- a/src/Queues.cpp +++ b/src/Queues.cpp @@ -6,7 +6,6 @@ #include "Rfid.h" QueueHandle_t gRfidCardQueue; -QueueHandle_t gLedQueue; void Queues_Init(void) { // Create queues @@ -15,9 +14,4 @@ void Queues_Init(void) { if (gRfidCardQueue == NULL) { Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Rfid"); } - - gLedQueue = xQueueCreate(1, sizeof(uint8_t)); - if (gLedQueue == NULL) { - Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Led"); - } } diff --git a/src/Queues.h b/src/Queues.h index c6597621..6425ea09 100644 --- a/src/Queues.h +++ b/src/Queues.h @@ -1,6 +1,5 @@ #pragma once extern QueueHandle_t gRfidCardQueue; -extern QueueHandle_t gLedQueue; void Queues_Init(void); diff --git a/src/main.cpp b/src/main.cpp index 7253011d..07f6baa9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -231,12 +231,10 @@ void loop() { Ftp_Cyclic(); RotaryEncoder_Cyclic(); } - vTaskDelay(portTICK_PERIOD_MS * 1u); AudioPlayer_Cyclic(); - vTaskDelay(portTICK_PERIOD_MS * 1u); + Led_Cyclic(); Battery_Cyclic(); Button_Cyclic(); - vTaskDelay(portTICK_PERIOD_MS * 1u); System_Cyclic(); Rfid_PreferenceLookupHandler(); @@ -253,9 +251,10 @@ void loop() { } IrReceiver_Cyclic(); - vTaskDelay(portTICK_PERIOD_MS * 2u); #ifdef HALLEFFECT_SENSOR_ENABLE gHallEffectSensor.cyclic(); #endif + + vTaskDelay(portTICK_PERIOD_MS * 5u); } From 2b6e18f91516181b738e405507bd042b1c3da644 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Fri, 16 May 2025 11:11:53 +0200 Subject: [PATCH 08/27] more performant main-loop --- src/main.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7253011d..b6f38bad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -231,12 +231,9 @@ void loop() { Ftp_Cyclic(); RotaryEncoder_Cyclic(); } - vTaskDelay(portTICK_PERIOD_MS * 1u); AudioPlayer_Cyclic(); - vTaskDelay(portTICK_PERIOD_MS * 1u); Battery_Cyclic(); Button_Cyclic(); - vTaskDelay(portTICK_PERIOD_MS * 1u); System_Cyclic(); Rfid_PreferenceLookupHandler(); @@ -253,9 +250,10 @@ void loop() { } IrReceiver_Cyclic(); - vTaskDelay(portTICK_PERIOD_MS * 2u); #ifdef HALLEFFECT_SENSOR_ENABLE gHallEffectSensor.cyclic(); #endif + + vTaskDelay(portTICK_PERIOD_MS * 5u); } From fa2c7a5a1a6b23c1cf4648afedc32b45ff7828c3 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Fri, 16 May 2025 19:52:13 +0200 Subject: [PATCH 09/27] some cleanup. No flicker at all anymore --- src/Led.cpp | 1 - src/Led.h | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Led.cpp b/src/Led.cpp index c74b4a6a..2cb7bc4a 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -159,7 +159,6 @@ void Led_Init(void) { FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); FastLED.setBrightness(gLedSettings.Led_Brightness); FastLED.setDither(DISABLE_DITHER); - FastLED.setMaxRefreshRate(120); // limit LED refresh rate to 120Hz (less likely to cause flickering) leds_active = true; #endif } diff --git a/src/Led.h b/src/Led.h index ee6711eb..2062259f 100644 --- a/src/Led.h +++ b/src/Led.h @@ -62,9 +62,10 @@ struct AnimationReturnType { #define LED_INITIAL_BRIGHTNESS 16u #define LED_INITIAL_NIGHT_BRIGHTNESS 2u - #define FASTLED_WS2812_T1 350 // original 250 - changed - #define FASTLED_WS2812_T2 700 // original 625 - changed - #define FASTLED_WS2812_T3 150 // original 375 - changed + #define FASTLED_WS2812_T1 250 // original 250 + #define FASTLED_WS2812_T2 625 // original 625 + #define FASTLED_WS2812_T3 375 // original 375 + #define FASTLED_LED_OVERCLOCK 1.0f // original 1.0f #include From 66555c89d7ec830d04da65c19f25311c363ca173 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Fri, 16 May 2025 22:18:52 +0200 Subject: [PATCH 10/27] separate cores more strictly --- platformio.ini | 2 +- sdkconfig.defaults | 2 +- src/AudioPlayer.cpp | 2 ++ src/Led.cpp | 1 + src/RfidMfrc522.cpp | 2 +- src/RfidPn5180.cpp | 2 +- src/main.cpp | 2 +- 7 files changed, 8 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index 3977b701..f53a85e8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -53,7 +53,7 @@ board_build.embed_txtfiles = managed_components/espressif__esp_rainmaker/server_certs/rmaker_ota_server.crt build_flags = - -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 + -DCONFIG_ASYNC_TCP_RUNNING_CORE=0 -DCONFIG_ASYNC_TCP_USE_WDT=1 ; -DCORE_DEBUG_LEVEL=6 -std=c++17 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 57e4ad1e..99ff073c 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -5,6 +5,7 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_AUTOSTART_ARDUINO=y +CONFIG_ARDUINO_EVENT_RUN_CORE0=y CONFIG_ARDUHAL_ESP_LOG=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y @@ -78,7 +79,6 @@ CONFIG_MBEDTLS_SSL_PROTO_DTLS=y CONFIG_MBEDTLS_CAMELLIA_C=y CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED=y CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED=y -CONFIG_MQTT_USE_CORE_1=y CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=2048 CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=10 CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=2 diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 7bd1ba76..53902c9e 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -202,6 +202,8 @@ void AudioPlayer_Init(void) { gPrefsSettings.getChar("gainLowPass", 0), gPrefsSettings.getChar("gainBandPass", 0), gPrefsSettings.getChar("gainHighPass", 0)); + + audio->setAudioTaskCore(1); } void AudioPlayer_Exit(void) { diff --git a/src/Led.cpp b/src/Led.cpp index 2cb7bc4a..728f8a9f 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -159,6 +159,7 @@ void Led_Init(void) { FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); FastLED.setBrightness(gLedSettings.Led_Brightness); FastLED.setDither(DISABLE_DITHER); + FastLED.setMaxRefreshRate(120); leds_active = true; #endif } diff --git a/src/RfidMfrc522.cpp b/src/RfidMfrc522.cpp index 0b11db7f..89b672c2 100644 --- a/src/RfidMfrc522.cpp +++ b/src/RfidMfrc522.cpp @@ -59,7 +59,7 @@ void Rfid_Init(void) { NULL, /* Task input parameter */ 1 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ + 0 /* Core where the task should run */ ); #endif } diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index 692d5d46..0235f6be 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -98,7 +98,7 @@ void Rfid_Init(void) { NULL, /* Task input parameter */ 1 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ + 0 /* Core where the task should run */ ); } diff --git a/src/main.cpp b/src/main.cpp index 07f6baa9..f137b5a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -256,5 +256,5 @@ void loop() { gHallEffectSensor.cyclic(); #endif - vTaskDelay(portTICK_PERIOD_MS * 5u); + vTaskDelay(portTICK_PERIOD_MS * 6u); } From 82098d1f0e9c9f5403e339daf3ab06526e598667 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sat, 17 May 2025 19:22:39 +0200 Subject: [PATCH 11/27] save wip --- platformio.ini | 5 +++-- sdkconfig.defaults | 1 - src/Led.cpp | 2 +- src/Led.h | 10 ++++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index f53a85e8..3ffe9eee 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,7 +33,8 @@ lib_deps = https://github.com/schreibfaul1/ESP32-audioI2S.git#e008d56 ; v3.2.0 (15.05.2025) https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f - https://github.com/FastLED/FastLED.git#3b63b17 ; v3.9.7 + ;https://github.com/FastLED/FastLED.git#b0f1447 ; v3.9.16 + https://github.com/Joe91/FastLED.git#bdf8c6a ; v3.9.16 (fork) https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 @@ -53,7 +54,7 @@ board_build.embed_txtfiles = managed_components/espressif__esp_rainmaker/server_certs/rmaker_ota_server.crt build_flags = - -DCONFIG_ASYNC_TCP_RUNNING_CORE=0 + -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 -DCONFIG_ASYNC_TCP_USE_WDT=1 ; -DCORE_DEBUG_LEVEL=6 -std=c++17 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 99ff073c..4f4453ed 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -5,7 +5,6 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_AUTOSTART_ARDUINO=y -CONFIG_ARDUINO_EVENT_RUN_CORE0=y CONFIG_ARDUHAL_ESP_LOG=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y diff --git a/src/Led.cpp b/src/Led.cpp index 728f8a9f..b8612816 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -159,7 +159,7 @@ void Led_Init(void) { FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); FastLED.setBrightness(gLedSettings.Led_Brightness); FastLED.setDither(DISABLE_DITHER); - FastLED.setMaxRefreshRate(120); + FastLED.setMaxRefreshRate(200); leds_active = true; #endif } diff --git a/src/Led.h b/src/Led.h index 2062259f..dbe36f1f 100644 --- a/src/Led.h +++ b/src/Led.h @@ -62,10 +62,12 @@ struct AnimationReturnType { #define LED_INITIAL_BRIGHTNESS 16u #define LED_INITIAL_NIGHT_BRIGHTNESS 2u - #define FASTLED_WS2812_T1 250 // original 250 - #define FASTLED_WS2812_T2 625 // original 625 - #define FASTLED_WS2812_T3 375 // original 375 - #define FASTLED_LED_OVERCLOCK 1.0f // original 1.0f +// #define FASTLED_WS2812_T1 250 // original 250 +// #define FASTLED_WS2812_T2 625 // original 625 +// #define FASTLED_WS2812_T3 375 // original 375 +// #define FASTLED_ALLOW_INTERRUPTS 0 +// #define FASTLED_LED_OVERCLOCK 1.0f // original 1.0f +// #define FASTLED_ESP32_USE_CLOCKLESS_SPI 1 #include From 5c6e3b462fa38b551626195e0678ba49ce9474e0 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sat, 17 May 2025 19:52:12 +0200 Subject: [PATCH 12/27] separate cores more strictly --- platformio.ini | 3 ++- sdkconfig.defaults | 1 - src/AudioPlayer.cpp | 2 ++ src/Led.cpp | 2 +- src/RfidMfrc522.cpp | 2 +- src/RfidPn5180.cpp | 2 +- src/main.cpp | 2 +- 7 files changed, 8 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index 3977b701..3ffe9eee 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,7 +33,8 @@ lib_deps = https://github.com/schreibfaul1/ESP32-audioI2S.git#e008d56 ; v3.2.0 (15.05.2025) https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f - https://github.com/FastLED/FastLED.git#3b63b17 ; v3.9.7 + ;https://github.com/FastLED/FastLED.git#b0f1447 ; v3.9.16 + https://github.com/Joe91/FastLED.git#bdf8c6a ; v3.9.16 (fork) https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 57e4ad1e..4f4453ed 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -78,7 +78,6 @@ CONFIG_MBEDTLS_SSL_PROTO_DTLS=y CONFIG_MBEDTLS_CAMELLIA_C=y CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED=y CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED=y -CONFIG_MQTT_USE_CORE_1=y CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=2048 CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=10 CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=2 diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 7bd1ba76..53902c9e 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -202,6 +202,8 @@ void AudioPlayer_Init(void) { gPrefsSettings.getChar("gainLowPass", 0), gPrefsSettings.getChar("gainBandPass", 0), gPrefsSettings.getChar("gainHighPass", 0)); + + audio->setAudioTaskCore(1); } void AudioPlayer_Exit(void) { diff --git a/src/Led.cpp b/src/Led.cpp index d44046b9..ec1fb4a2 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -357,7 +357,7 @@ static void Led_Task(void *parameter) { FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); FastLED.setBrightness(gLedSettings.Led_Brightness); FastLED.setDither(DISABLE_DITHER); - FastLED.setMaxRefreshRate(120); // limit LED refresh rate to 120Hz (less likely to cause flickering) + FastLED.setMaxRefreshRate(200); // limit LED refresh rate to 120Hz (less likely to cause flickering) LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; diff --git a/src/RfidMfrc522.cpp b/src/RfidMfrc522.cpp index 0b11db7f..89b672c2 100644 --- a/src/RfidMfrc522.cpp +++ b/src/RfidMfrc522.cpp @@ -59,7 +59,7 @@ void Rfid_Init(void) { NULL, /* Task input parameter */ 1 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ + 0 /* Core where the task should run */ ); #endif } diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index 692d5d46..0235f6be 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -98,7 +98,7 @@ void Rfid_Init(void) { NULL, /* Task input parameter */ 1 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ + 0 /* Core where the task should run */ ); } diff --git a/src/main.cpp b/src/main.cpp index b6f38bad..d1590728 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -255,5 +255,5 @@ void loop() { gHallEffectSensor.cyclic(); #endif - vTaskDelay(portTICK_PERIOD_MS * 5u); + vTaskDelay(portTICK_PERIOD_MS * 6u); } From b1dba8083c3d3068159bd9b3ecfffff0918532af Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sun, 18 May 2025 07:33:32 +0200 Subject: [PATCH 13/27] use original positioin of loop again and add pause-mechanism again --- src/AudioPlayer.cpp | 22 ++++++++++++++++------ src/AudioPlayer.h | 3 +++ src/System.h | 1 - src/Web.cpp | 10 +++++----- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 53902c9e..ff9726fa 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -32,8 +32,6 @@ #define AUDIOPLAYER_VOLUME_INIT 3u playProps gPlayProperties; -TaskHandle_t AudioTaskHandle; -// uint32_t cnt123 = 0; // Playlist static playlistSortMode AudioPlayer_PlaylistSortMode = AUDIOPLAYER_PLAYLIST_SORT_MODE_DEFAULT; @@ -82,6 +80,7 @@ bool audioReturnCode; uint32_t AudioPlayer_LastPlaytimeStatsTimestamp = 0u; Playlist *newPlayList = nullptr; bool newPlayListAvailable = false; +bool audio_active = false; static void AudioPlayer_HeadphoneVolumeManager(void); static std::optional AudioPlayer_ReturnPlaylistFromWebstream(const char *_webUrl); @@ -93,6 +92,13 @@ static void AudioPlayer_RandomizePlaylist(Playlist *playlist); static size_t AudioPlayer_NvsRfidWriteWrapper(const char *_rfidCardId, const char *_track, const uint32_t _playPosition, const uint8_t _playMode, const uint16_t _trackLastPlayed, const uint16_t _numberOfTracks); static void AudioPlayer_ClearCover(void); +void Audio_TaskPause(void) { + bool audio_active = false; +} +void Audio_TaskResume(void) { + bool audio_active = true; +} + void AudioPlayer_Init(void) { // create audio object #ifdef BOARD_HAS_PSRAM @@ -204,6 +210,8 @@ void AudioPlayer_Init(void) { gPrefsSettings.getChar("gainHighPass", 0)); audio->setAudioTaskCore(1); + + audio_active = true; } void AudioPlayer_Exit(void) { @@ -223,6 +231,10 @@ void AudioPlayer_Exit(void) { static uint32_t lastPlayingTimestamp = 0; void AudioPlayer_Cyclic(void) { + if (!audio_active) { + return; + } + AudioPlayer_HeadphoneVolumeManager(); if ((millis() - lastPlayingTimestamp >= 1000) && gPlayProperties.playMode != NO_PLAYLIST && gPlayProperties.playMode != BUSY && !gPlayProperties.pausePlay) { // audio is playing, update the playtime since start @@ -409,9 +421,6 @@ void AudioPlayer_HeadphoneVolumeManager(void) { // Function to play music as task void AudioPlayer_Loop() { - - audio->loop(); - // Update playtime stats every 250 ms if ((millis() - AudioPlayer_LastPlaytimeStatsTimestamp) > 250) { AudioPlayer_LastPlaytimeStatsTimestamp = millis(); @@ -860,7 +869,8 @@ void AudioPlayer_Loop() { audio->setTone(gPlayProperties.gainLowPass, gPlayProperties.gainBandPass, gPlayProperties.gainHighPass); } - // audio->loop(); was here before + audio->loop(); // Call audio-loop function to process incoming data + if (gPlayProperties.playlistFinished || gPlayProperties.pausePlay) { } else { System_UpdateActivityTimer(); // Refresh if playlist is active so uC will not fall asleep due to reaching inactivity-time diff --git a/src/AudioPlayer.h b/src/AudioPlayer.h index ef213619..045c7190 100644 --- a/src/AudioPlayer.h +++ b/src/AudioPlayer.h @@ -53,6 +53,9 @@ typedef struct { // Bit field extern playProps gPlayProperties; +void Audio_TaskPause(void); +void Audio_TaskResume(void); + void AudioPlayer_Init(void); void AudioPlayer_Exit(void); void AudioPlayer_Cyclic(void); diff --git a/src/System.h b/src/System.h index be9f1952..96fdda08 100644 --- a/src/System.h +++ b/src/System.h @@ -3,7 +3,6 @@ extern Preferences gPrefsRfid; extern Preferences gPrefsSettings; -extern TaskHandle_t AudioTaskHandle; void System_Init_LPCD(void); void System_Init(void); diff --git a/src/Web.cpp b/src/Web.cpp index a7f5352a..a9faae3a 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -442,7 +442,7 @@ void webserverStart(void) { if (!index) { // pause some tasks to get more free CPU time for the upload - vTaskSuspend(AudioTaskHandle); + Audio_TaskPause(); Led_TaskPause(); Rfid_TaskPause(); Update.begin(); @@ -456,7 +456,7 @@ void webserverStart(void) { Update.end(true); // resume the paused tasks Led_TaskResume(); - vTaskResume(AudioTaskHandle); + Audio_TaskResume(); Rfid_TaskResume(); Log_Println(fwEnd, LOGLEVEL_NOTICE); if (Update.hasError()) { @@ -1639,7 +1639,7 @@ void explorerHandleFileStorageTask(void *parameter) { uploadFile.setBufferSize(chunk_size); // pause some tasks to get more free CPU time for the upload - vTaskSuspend(AudioTaskHandle); + Audio_TaskPause(); Led_TaskPause(); Rfid_TaskPause(); @@ -1678,7 +1678,7 @@ void explorerHandleFileStorageTask(void *parameter) { free(parameter); // resume the paused tasks Led_TaskResume(); - vTaskResume(AudioTaskHandle); + Audio_TaskResume(); Rfid_TaskResume(); // destroy double buffer memory, since the upload was interrupted destroyDoubleBuffer(); @@ -1693,7 +1693,7 @@ void explorerHandleFileStorageTask(void *parameter) { free(parameter); // resume the paused tasks Led_TaskResume(); - vTaskResume(AudioTaskHandle); + Audio_TaskResume(); Rfid_TaskResume(); // send signal to upload function to terminate xSemaphoreGive(explorerFileUploadFinished); From 81a237cd4ab15b34fc04495401457f3268b54906 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sun, 18 May 2025 13:59:52 +0200 Subject: [PATCH 14/27] fix from wolle (set file pos works again) --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 3ffe9eee..26e231ae 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,7 +30,7 @@ extra_scripts = pre:updateSdkConfig.py pre:processHtml.py lib_deps = - https://github.com/schreibfaul1/ESP32-audioI2S.git#e008d56 ; v3.2.0 (15.05.2025) + https://github.com/schreibfaul1/ESP32-audioI2S.git#c694298 ; v3.2.0 + bugfix setpos (18.05.2025) https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f ;https://github.com/FastLED/FastLED.git#b0f1447 ; v3.9.16 From 467cbe2199d6942f206e17f0a1b88191e770df4e Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sun, 18 May 2025 19:42:08 +0200 Subject: [PATCH 15/27] clean core-separation --- platformio.ini | 2 +- sdkconfig.defaults | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 26e231ae..f6c25d14 100644 --- a/platformio.ini +++ b/platformio.ini @@ -54,7 +54,7 @@ board_build.embed_txtfiles = managed_components/espressif__esp_rainmaker/server_certs/rmaker_ota_server.crt build_flags = - -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 + -DCONFIG_ASYNC_TCP_RUNNING_CORE=0 -DCONFIG_ASYNC_TCP_USE_WDT=1 ; -DCORE_DEBUG_LEVEL=6 -std=c++17 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 4f4453ed..26918f14 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -5,6 +5,8 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_AUTOSTART_ARDUINO=y +CONFIG_ARDUINO_EVENT_RUN_CORE0=y +CONFIG_ARDUINO_SERIAL_EVENT_RUN_CORE0=y CONFIG_ARDUHAL_ESP_LOG=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y From 5f8591beff0984f4a87dfab44c052a12d838f215 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sun, 18 May 2025 20:48:38 +0200 Subject: [PATCH 16/27] don't stop the leds or music anymore during upload. Reduce diffs --- src/RfidMfrc522.cpp | 2 +- src/RfidPn5180.cpp | 2 +- src/Web.cpp | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/RfidMfrc522.cpp b/src/RfidMfrc522.cpp index 89b672c2..bb7bfa04 100644 --- a/src/RfidMfrc522.cpp +++ b/src/RfidMfrc522.cpp @@ -57,7 +57,7 @@ void Rfid_Init(void) { "rfid", /* Name of the task */ 2048, /* Stack size in words */ NULL, /* Task input parameter */ - 1 | portPRIVILEGE_BIT, /* Priority of the task */ + 2 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ 0 /* Core where the task should run */ ); diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index 0235f6be..5005fa1c 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -96,7 +96,7 @@ void Rfid_Init(void) { "rfid", /* Name of the task */ 3072, /* Stack size in words */ NULL, /* Task input parameter */ - 1 | portPRIVILEGE_BIT, /* Priority of the task */ + 2 | portPRIVILEGE_BIT, /* Priority of the task */ &rfidTaskHandle, /* Task handle. */ 0 /* Core where the task should run */ ); diff --git a/src/Web.cpp b/src/Web.cpp index a9faae3a..931bf19b 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -442,8 +442,8 @@ void webserverStart(void) { if (!index) { // pause some tasks to get more free CPU time for the upload - Audio_TaskPause(); - Led_TaskPause(); + // Audio_TaskPause(); + // Led_TaskPause(); Rfid_TaskPause(); Update.begin(); Log_Println(fwStart, LOGLEVEL_NOTICE); @@ -455,8 +455,8 @@ void webserverStart(void) { if (final) { Update.end(true); // resume the paused tasks - Led_TaskResume(); - Audio_TaskResume(); + // Led_TaskResume(); + // Audio_TaskResume(); Rfid_TaskResume(); Log_Println(fwEnd, LOGLEVEL_NOTICE); if (Update.hasError()) { @@ -1639,8 +1639,8 @@ void explorerHandleFileStorageTask(void *parameter) { uploadFile.setBufferSize(chunk_size); // pause some tasks to get more free CPU time for the upload - Audio_TaskPause(); - Led_TaskPause(); + // Audio_TaskPause(); + // Led_TaskPause(); Rfid_TaskPause(); for (;;) { @@ -1677,8 +1677,8 @@ void explorerHandleFileStorageTask(void *parameter) { Log_Println(webTxCanceled, LOGLEVEL_ERROR); free(parameter); // resume the paused tasks - Led_TaskResume(); - Audio_TaskResume(); + // Led_TaskResume(); + // Audio_TaskResume(); Rfid_TaskResume(); // destroy double buffer memory, since the upload was interrupted destroyDoubleBuffer(); @@ -1692,8 +1692,8 @@ void explorerHandleFileStorageTask(void *parameter) { } free(parameter); // resume the paused tasks - Led_TaskResume(); - Audio_TaskResume(); + // Led_TaskResume(); + // Audio_TaskResume(); Rfid_TaskResume(); // send signal to upload function to terminate xSemaphoreGive(explorerFileUploadFinished); From d9d3e9edf8004ba2bad8d0e5b5c05186e673b2a6 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sun, 18 May 2025 21:54:38 +0200 Subject: [PATCH 17/27] fix invalid reference --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index f6c25d14..a163ad53 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,7 +34,7 @@ lib_deps = https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f ;https://github.com/FastLED/FastLED.git#b0f1447 ; v3.9.16 - https://github.com/Joe91/FastLED.git#bdf8c6a ; v3.9.16 (fork) + https://github.com/Joe91/FastLED.git#3ab1e7e ; v3.9.16 (fork) https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 From 00b7b83b95e3f112dc42686679989d1de83c3304 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Mon, 19 May 2025 21:39:48 +0200 Subject: [PATCH 18/27] create full topic dynamically --- src/Mqtt.cpp | 341 +++++++++++++++++++++++++++---------------------- src/settings.h | 52 ++++---- 2 files changed, 217 insertions(+), 176 deletions(-) diff --git a/src/Mqtt.cpp b/src/Mqtt.cpp index 97c7a09a..01f6e54f 100644 --- a/src/Mqtt.cpp +++ b/src/Mqtt.cpp @@ -29,6 +29,7 @@ String gMqttServer = "192.168.2.43"; // IP-address of MQTT-server (if not found String gMqttUser = "mqtt-user"; // MQTT-user String gMqttPassword = "mqtt-password"; // MQTT-password uint16_t gMqttPort = 1883; // MQTT-Port +constexpr uint8_t MQTT_TOPIC_MAX_LENGTH = 128u; // Maximal length of MQTT-topic #endif // MQTT @@ -137,6 +138,27 @@ void Mqtt_OnWifiConnected(void) { #endif } +#ifdef MQTT_ENABLE +const char *Mqtt_GetTopic(const char *topic, bool isStateTopic) { + static char out_string[MQTT_TOPIC_MAX_LENGTH]; // Static buffer to hold the result + + // Build the topic string + if (!isStateTopic) { + snprintf(out_string, MQTT_TOPIC_MAX_LENGTH, "%s/%s/%s", commandWord, gMqttClientId.c_str(), topic); + } else { + snprintf(out_string, MQTT_TOPIC_MAX_LENGTH, "%s/%s/%s", stateWord, gMqttClientId.c_str(), topic); + } + + return out_string; // Return the static buffer +} +const char *Mqtt_GetStateTopic(const char *topic) { + return Mqtt_GetTopic(topic, true); +} +const char *Mqtt_GetCommandTopic(const char *topic) { + return Mqtt_GetTopic(topic, false); +} +#endif + void Mqtt_Exit(void) { #ifdef MQTT_ENABLE Log_Println("shutdown MQTT..", LOGLEVEL_NOTICE); @@ -157,7 +179,7 @@ bool publishMqtt(const char *topic, const char *payload, bool retained) { #ifdef MQTT_ENABLE if (strcmp(topic, "") != 0) { int qos = 0; - int ret = esp_mqtt_client_publish(mqtt_client, topic, payload, 0, qos, retained); + int ret = esp_mqtt_client_publish(mqtt_client, Mqtt_GetStateTopic(topic), payload, 0, qos, retained); // int ret = esp_mqtt_client_enqueue(mqtt_client, topic, payload, 0, qos, retained, true); return ret == 0; } @@ -214,28 +236,28 @@ void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event int qos = 0; // Deepsleep-subscription - esp_mqtt_client_subscribe(client, topicSleepCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicSleepCmnd), qos); // RFID-"mqtt_debug"-ID-subscription - esp_mqtt_client_subscribe(client, topicRfidCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicRfidCmnd), qos); // Loudness-subscription - esp_mqtt_client_subscribe(client, topicLoudnessCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicLoudnessCmnd), qos); // Sleep-Timer-subscription - esp_mqtt_client_subscribe(client, topicSleepTimerCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicSleepTimerCmnd), qos); // Next/previous/stop/play-track-subscription - esp_mqtt_client_subscribe(client, topicTrackControlCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicTrackControlCmnd), qos); // Lock controls - esp_mqtt_client_subscribe(client, topicLockControlsCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicLockControlsCmnd), qos); // Current repeat-Mode - esp_mqtt_client_subscribe(client, topicRepeatModeCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicRepeatModeCmnd), qos); // LED-brightness - esp_mqtt_client_subscribe(client, topicLedBrightnessCmnd, qos); + esp_mqtt_client_subscribe(client, Mqtt_GetCommandTopic(topicLedBrightnessCmnd), qos); // Publish current state publishMqtt(topicState, "Online", false); @@ -297,166 +319,181 @@ void Mqtt_ClientCallback(const char *topic_buf, uint32_t topic_length, const cha Log_Printf(LOGLEVEL_INFO, mqttMsgReceived, topic_str.c_str(), payload_str.c_str()); - // Go to sleep? - if (topic_str == topicSleepCmnd) { - if (payload_str == "OFF" || payload_str == "0") { - System_RequestSleep(); + // Define the prefix to match (e.g., "commandWord/gMqttClientId/") + char prefix[MQTT_TOPIC_MAX_LENGTH]; + snprintf(prefix, sizeof(prefix), "%s/%s/", commandWord, gMqttClientId.c_str()); + + // Check if the topic starts with the prefix + if (strncmp(topic_str.c_str(), prefix, strlen(prefix)) == 0) { + + // Remove the prefix from the topic + std::string reduced_topic_str = std::string(topic_str.c_str() + strlen(prefix)); + + // Go to sleep? + if (reduced_topic_str == topicSleepCmnd) { + if (payload_str == "OFF" || payload_str == "0") { + System_RequestSleep(); + } } - } - // New track to play? Take RFID-ID as input - else if (topic_str == topicRfidCmnd) { - if (payload_str.size() >= (cardIdStringSize - 1)) { - xQueueSend(gRfidCardQueue, payload_str.data(), 0); - } else { - System_IndicateError(); + // New track to play? Take RFID-ID as input + else if (reduced_topic_str == topicRfidCmnd) { + if (payload_str.size() >= (cardIdStringSize - 1)) { + xQueueSend(gRfidCardQueue, payload_str.data(), 0); + } else { + System_IndicateError(); + } } - } - // Loudness to change? - else if (topic_str == topicLoudnessCmnd) { - unsigned long vol = toNumber(payload_str); - AudioPlayer_SetVolume(vol, true); - } - // Modify sleep-timer? - else if (topic_str == topicSleepTimerCmnd) { - if (gPlayProperties.playMode == NO_PLAYLIST) { // Don't allow sleep-modications if no playlist is active - Log_Println(modificatorNotallowedWhenIdle, LOGLEVEL_INFO); - publishMqtt(topicSleepState, static_cast(0), false); - System_IndicateError(); - return; + // Loudness to change? + else if (reduced_topic_str == topicLoudnessCmnd) { + unsigned long vol = toNumber(payload_str); + AudioPlayer_SetVolume(vol, true); } - if (payload_str == "EOP") { - gPlayProperties.sleepAfterPlaylist = true; - Log_Println(sleepTimerEOP, LOGLEVEL_NOTICE); - publishMqtt(topicSleepTimerState, "EOP", false); - Led_SetNightmode(true); - System_IndicateOk(); - return; - } else if (payload_str == "EOT") { - gPlayProperties.sleepAfterCurrentTrack = true; - Log_Println(sleepTimerEOT, LOGLEVEL_NOTICE); - publishMqtt(topicSleepTimerState, "EOT", false); - Led_SetNightmode(true); - System_IndicateOk(); - return; - } else if (payload_str == "EO5T") { - if (gPlayProperties.playMode == NO_PLAYLIST || !gPlayProperties.playlist) { - Log_Println(modificatorNotallowedWhenIdle, LOGLEVEL_NOTICE); + // Modify sleep-timer? + else if (reduced_topic_str == topicSleepTimerCmnd) { + if (gPlayProperties.playMode == NO_PLAYLIST) { // Don't allow sleep-modications if no playlist is active + Log_Println(modificatorNotallowedWhenIdle, LOGLEVEL_INFO); + publishMqtt(topicSleepState, static_cast(0), false); System_IndicateError(); return; } - if ((gPlayProperties.playlist->size() - 1) >= (gPlayProperties.currentTrackNumber + 5)) { - gPlayProperties.playUntilTrackNumber = gPlayProperties.currentTrackNumber + 5; - } else { - gPlayProperties.sleepAfterPlaylist = true; // If +5 tracks is > than active playlist, take end of current playlist - } - Log_Println(sleepTimerEO5, LOGLEVEL_NOTICE); - publishMqtt(topicSleepTimerState, "EO5T", false); - Led_SetNightmode(true); - System_IndicateOk(); - return; - } else if (payload_str == "0") { // Disable sleep after it was active previously - if (System_IsSleepTimerEnabled()) { - System_DisableSleepTimer(); - Log_Println(sleepTimerStop, LOGLEVEL_NOTICE); + if (payload_str == "EOP") { + gPlayProperties.sleepAfterPlaylist = true; + Log_Println(sleepTimerEOP, LOGLEVEL_NOTICE); + publishMqtt(topicSleepTimerState, "EOP", false); + Led_SetNightmode(true); System_IndicateOk(); - Led_SetNightmode(false); - publishMqtt(topicSleepState, static_cast(0), false); - gPlayProperties.sleepAfterPlaylist = false; - gPlayProperties.sleepAfterCurrentTrack = false; - gPlayProperties.playUntilTrackNumber = 0; - } else { - Log_Println(sleepTimerAlreadyStopped, LOGLEVEL_INFO); - System_IndicateError(); + return; + } else if (payload_str == "EOT") { + gPlayProperties.sleepAfterCurrentTrack = true; + Log_Println(sleepTimerEOT, LOGLEVEL_NOTICE); + publishMqtt(topicSleepTimerState, "EOT", false); + Led_SetNightmode(true); + System_IndicateOk(); + return; + } else if (payload_str == "EO5T") { + if (gPlayProperties.playMode == NO_PLAYLIST || !gPlayProperties.playlist) { + Log_Println(modificatorNotallowedWhenIdle, LOGLEVEL_NOTICE); + System_IndicateError(); + return; + } + if ((gPlayProperties.playlist->size() - 1) >= (gPlayProperties.currentTrackNumber + 5)) { + gPlayProperties.playUntilTrackNumber = gPlayProperties.currentTrackNumber + 5; + } else { + gPlayProperties.sleepAfterPlaylist = true; // If +5 tracks is > than active playlist, take end of current playlist + } + Log_Println(sleepTimerEO5, LOGLEVEL_NOTICE); + publishMqtt(topicSleepTimerState, "EO5T", false); + Led_SetNightmode(true); + System_IndicateOk(); + return; + } else if (payload_str == "0") { // Disable sleep after it was active previously + if (System_IsSleepTimerEnabled()) { + System_DisableSleepTimer(); + Log_Println(sleepTimerStop, LOGLEVEL_NOTICE); + System_IndicateOk(); + Led_SetNightmode(false); + publishMqtt(topicSleepState, static_cast(0), false); + gPlayProperties.sleepAfterPlaylist = false; + gPlayProperties.sleepAfterCurrentTrack = false; + gPlayProperties.playUntilTrackNumber = 0; + } else { + Log_Println(sleepTimerAlreadyStopped, LOGLEVEL_INFO); + System_IndicateError(); + } + return; } - return; - } - System_SetSleepTimer(toNumber(payload_str)); - Log_Printf(LOGLEVEL_NOTICE, sleepTimerSetTo, System_GetSleepTimer()); - System_IndicateOk(); + System_SetSleepTimer(toNumber(payload_str)); + Log_Printf(LOGLEVEL_NOTICE, sleepTimerSetTo, System_GetSleepTimer()); + System_IndicateOk(); - gPlayProperties.sleepAfterPlaylist = false; - gPlayProperties.sleepAfterCurrentTrack = false; - } - // Track-control (pause/play, stop, first, last, next, previous) - else if (topic_str == topicTrackControlCmnd) { - uint8_t controlCommand = toNumber(payload_str); - AudioPlayer_SetTrackControl(controlCommand); - } + gPlayProperties.sleepAfterPlaylist = false; + gPlayProperties.sleepAfterCurrentTrack = false; + } + // Track-control (pause/play, stop, first, last, next, previous) + else if (reduced_topic_str == topicTrackControlCmnd) { + uint8_t controlCommand = toNumber(payload_str); + AudioPlayer_SetTrackControl(controlCommand); + } - // Check if controls should be locked - else if (topic_str == topicLockControlsCmnd) { - if (payload_str == "OFF") { - System_SetLockControls(false); - Log_Println(allowButtons, LOGLEVEL_NOTICE); - publishMqtt(topicLockControlsState, "OFF", false); - System_IndicateOk(); - } else if (payload_str == "ON") { - System_SetLockControls(true); - Log_Println(lockButtons, LOGLEVEL_NOTICE); - publishMqtt(topicLockControlsState, "ON", false); - System_IndicateOk(); + // Check if controls should be locked + else if (reduced_topic_str == topicLockControlsCmnd) { + if (payload_str == "OFF") { + System_SetLockControls(false); + Log_Println(allowButtons, LOGLEVEL_NOTICE); + publishMqtt(topicLockControlsState, "OFF", false); + System_IndicateOk(); + } else if (payload_str == "ON") { + System_SetLockControls(true); + Log_Println(lockButtons, LOGLEVEL_NOTICE); + publishMqtt(topicLockControlsState, "ON", false); + System_IndicateOk(); + } } - } - // Check if playmode should be adjusted - else if (topic_str == topicRepeatModeCmnd) { - uint8_t repeatMode = toNumber(payload_str); - Log_Printf(LOGLEVEL_NOTICE, "Repeat: %d", repeatMode); - if (gPlayProperties.playMode != NO_PLAYLIST) { - if (gPlayProperties.playMode == NO_PLAYLIST) { - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); - Log_Println(noPlaylistNotAllowedMqtt, LOGLEVEL_ERROR); - System_IndicateError(); - } else { - switch (repeatMode) { - case NO_REPEAT: - gPlayProperties.repeatCurrentTrack = false; - gPlayProperties.repeatPlaylist = false; - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); - Log_Println(modeRepeatNone, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - case TRACK: - gPlayProperties.repeatCurrentTrack = true; - gPlayProperties.repeatPlaylist = false; - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); - Log_Println(modeRepeatTrack, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - case PLAYLIST: - gPlayProperties.repeatCurrentTrack = false; - gPlayProperties.repeatPlaylist = true; - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); - Log_Println(modeRepeatPlaylist, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - case TRACK_N_PLAYLIST: - gPlayProperties.repeatCurrentTrack = true; - gPlayProperties.repeatPlaylist = true; - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); - Log_Println(modeRepeatTracknPlaylist, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - default: - System_IndicateError(); - publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); - break; + // Check if playmode should be adjusted + else if (reduced_topic_str == topicRepeatModeCmnd) { + uint8_t repeatMode = toNumber(payload_str); + Log_Printf(LOGLEVEL_NOTICE, "Repeat: %d", repeatMode); + if (gPlayProperties.playMode != NO_PLAYLIST) { + if (gPlayProperties.playMode == NO_PLAYLIST) { + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + Log_Println(noPlaylistNotAllowedMqtt, LOGLEVEL_ERROR); + System_IndicateError(); + } else { + switch (repeatMode) { + case NO_REPEAT: + gPlayProperties.repeatCurrentTrack = false; + gPlayProperties.repeatPlaylist = false; + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + Log_Println(modeRepeatNone, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + case TRACK: + gPlayProperties.repeatCurrentTrack = true; + gPlayProperties.repeatPlaylist = false; + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + Log_Println(modeRepeatTrack, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + case PLAYLIST: + gPlayProperties.repeatCurrentTrack = false; + gPlayProperties.repeatPlaylist = true; + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + Log_Println(modeRepeatPlaylist, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + case TRACK_N_PLAYLIST: + gPlayProperties.repeatCurrentTrack = true; + gPlayProperties.repeatPlaylist = true; + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + Log_Println(modeRepeatTracknPlaylist, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + default: + System_IndicateError(); + publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); + break; + } } } } - } - // Check if LEDs should be dimmed - else if (topic_str == topicLedBrightnessCmnd) { - Led_SetBrightness(toNumber(payload_str)); - } + // Check if LEDs should be dimmed + else if (reduced_topic_str == topicLedBrightnessCmnd) { + Led_SetBrightness(toNumber(payload_str)); + } - // Requested something that isn't specified? - else { + // Requested something that isn't specified? + else { + Log_Printf(LOGLEVEL_ERROR, noValidTopic, topic_str.c_str()); + System_IndicateError(); + } + } else { + // Topic doesn't start with the prefix Log_Printf(LOGLEVEL_ERROR, noValidTopic, topic_str.c_str()); System_IndicateError(); } diff --git a/src/settings.h b/src/settings.h index f1c0b5a8..303c06be 100644 --- a/src/settings.h +++ b/src/settings.h @@ -263,31 +263,35 @@ // (optional) Topics for MQTT #ifdef MQTT_ENABLE #define DEVICE_HOSTNAME "ESP32-ESPuino" // Name that is used for MQTT - constexpr const char topicSleepCmnd[] = "Cmnd/ESPuino/Sleep"; - constexpr const char topicSleepState[] = "State/ESPuino/Sleep"; - constexpr const char topicRfidCmnd[] = "Cmnd/ESPuino/Rfid"; - constexpr const char topicRfidState[] = "State/ESPuino/Rfid"; - constexpr const char topicTrackState[] = "State/ESPuino/Track"; - constexpr const char topicTrackControlCmnd[] = "Cmnd/ESPuino/TrackControl"; - constexpr const char topicCoverChangedState[] = "State/ESPuino/CoverChanged"; - constexpr const char topicLoudnessCmnd[] = "Cmnd/ESPuino/Loudness"; - constexpr const char topicLoudnessState[] = "State/ESPuino/Loudness"; - constexpr const char topicSleepTimerCmnd[] = "Cmnd/ESPuino/SleepTimer"; - constexpr const char topicSleepTimerState[] = "State/ESPuino/SleepTimer"; - constexpr const char topicState[] = "State/ESPuino/State"; - constexpr const char topicCurrentIPv4IP[] = "State/ESPuino/IPv4"; - constexpr const char topicLockControlsCmnd[] ="Cmnd/ESPuino/LockControls"; - constexpr const char topicLockControlsState[] ="State/ESPuino/LockControls"; - constexpr const char topicPlaymodeState[] = "State/ESPuino/Playmode"; - constexpr const char topicRepeatModeCmnd[] = "Cmnd/ESPuino/RepeatMode"; - constexpr const char topicRepeatModeState[] = "State/ESPuino/RepeatMode"; - constexpr const char topicLedBrightnessCmnd[] = "Cmnd/ESPuino/LedBrightness"; - constexpr const char topicLedBrightnessState[] = "State/ESPuino/LedBrightness"; - constexpr const char topicWiFiRssiState[] = "State/ESPuino/WifiRssi"; - constexpr const char topicSRevisionState[] = "State/ESPuino/SoftwareRevision"; + constexpr const char commandWord[] = "Cmnd"; + constexpr const char stateWord[] = "State"; + // Commands + constexpr const char topicSleepCmnd[] = "Sleep"; + constexpr const char topicRfidCmnd[] = "Rfid"; + constexpr const char topicTrackControlCmnd[] = "TrackControl"; + constexpr const char topicLoudnessCmnd[] = "Loudness"; + constexpr const char topicSleepTimerCmnd[] = "SleepTimer"; + constexpr const char topicLockControlsCmnd[] ="LockControls"; + constexpr const char topicRepeatModeCmnd[] = "RepeatMode"; + constexpr const char topicLedBrightnessCmnd[] = "LedBrightness"; + // States + constexpr const char topicSleepState[] = "Sleep"; + constexpr const char topicRfidState[] = "Rfid"; + constexpr const char topicTrackState[] = "Track"; + constexpr const char topicCoverChangedState[] = "CoverChanged"; + constexpr const char topicLoudnessState[] = "Loudness"; + constexpr const char topicSleepTimerState[] = "SleepTimer"; + constexpr const char topicState[] = "State"; + constexpr const char topicCurrentIPv4IP[] = "IPv4"; + constexpr const char topicLockControlsState[] ="LockControls"; + constexpr const char topicPlaymodeState[] = "Playmode"; + constexpr const char topicRepeatModeState[] = "RepeatMode"; + constexpr const char topicLedBrightnessState[] = "LedBrightness"; + constexpr const char topicWiFiRssiState[] = "WifiRssi"; + constexpr const char topicSRevisionState[] = "SoftwareRevision"; #ifdef BATTERY_MEASURE_ENABLE - constexpr const char topicBatteryVoltage[] = "State/ESPuino/Voltage"; - constexpr const char topicBatterySOC[] = "State/ESPuino/Battery"; + constexpr const char topicBatteryVoltage[] = "Voltage"; + constexpr const char topicBatterySOC[] = "Battery"; #endif #endif From 4301d8af1f67adfc44c71ed4e2e3e4da169108e3 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 22 May 2025 21:18:37 +0200 Subject: [PATCH 19/27] Revert "Merge branch 'remove_led-task' into remove_audio_task" This reverts commit 3c434348bd5801246cc308eda538236b26f4b545, reversing changes made to 5c6e3b462fa38b551626195e0678ba49ce9474e0. --- src/Led.cpp | 409 ++++++++++++++++++++++++++----------------------- src/Led.h | 10 +- src/Queues.cpp | 6 + src/Queues.h | 1 + src/main.cpp | 12 +- 5 files changed, 235 insertions(+), 203 deletions(-) diff --git a/src/Led.cpp b/src/Led.cpp index b8612816..4b328562 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -35,14 +35,8 @@ static uint8_t Led_savedBrightness; // global led settings static LedSettings gLedSettings; -static CRGB *leds = nullptr; -static CRGBSet *indicator = nullptr; -static uint8_t lastLedBrightness = 0; -bool leds_active = false; -bool led_settings_changed = false; -uint8_t numIndicatorLeds = 0; -uint8_t numControlLeds = 0; - +TaskHandle_t Led_TaskHandle; +static void Led_Task(void *parameter); static uint8_t Led_Address(uint8_t number); // animation-functions prototypes @@ -145,28 +139,35 @@ bool Led_LoadSettings(LedSettings &settings) { void Led_Init(void) { #ifdef NEOPIXEL_ENABLE + if (Led_TaskHandle) { + // if led task is already running notify to reload settings + uint8_t ledSettingsChanged = 1; + xQueueSend(gLedQueue, &ledSettingsChanged, 0); + return; + } + // load led settings from NVS Led_LoadSettings(gLedSettings); - led_settings_changed = true; - lastLedBrightness = gLedSettings.Led_Brightness; - numIndicatorLeds = gLedSettings.numIndicatorLeds; - numControlLeds = gLedSettings.numControlLeds; - // Allocate memory for LED arrays - leds = new CRGB[numIndicatorLeds + numControlLeds]; - indicator = new CRGBSet(leds, numIndicatorLeds); - // initialize FastLED - FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); - FastLED.setBrightness(gLedSettings.Led_Brightness); - FastLED.setDither(DISABLE_DITHER); - FastLED.setMaxRefreshRate(200); - leds_active = true; + xTaskCreatePinnedToCore( + Led_Task, /* Function to implement the task */ + "Led_Task", /* Name of the task */ + 2048, /* Stack size in words */ + NULL, /* Task input parameter */ + 1, /* Priority of the task */ + &Led_TaskHandle, /* Task handle. */ + 1 /* Core where the task should run */ + ); #endif } void Led_Exit(void) { #ifdef NEOPIXEL_ENABLE Log_Println("shutdown LED..", LOGLEVEL_NOTICE); + if (Led_TaskHandle) { + vTaskDelete(Led_TaskHandle); + Led_TaskHandle = NULL; + } // Turn off LEDs in order to avoid LEDs still glowing when ESP32 is in deepsleep FastLED.clear(true); #endif @@ -342,189 +343,209 @@ bool CheckForPowerButtonAnimation() { #endif #ifdef NEOPIXEL_ENABLE -void Led_Cyclic(void) { - static LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; - static LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; - static bool animationActive = false; - static int32_t animationTimer = 0; - static uint32_t animationStartTimestamp = 0; +static void Led_Task(void *parameter) { + static uint8_t lastLedBrightness = gLedSettings.Led_Brightness; + static CRGB *leds = nullptr; + static CRGBSet *indicator = nullptr; - // directly return if no LEDs are active - if (!leds_active) { - return; - } + uint8_t numIndicatorLeds = gLedSettings.numIndicatorLeds; + uint8_t numControlLeds = gLedSettings.numControlLeds; + // Allocate memory for LED arrays + leds = new CRGB[numIndicatorLeds + numControlLeds]; + indicator = new CRGBSet(leds, numIndicatorLeds); + // initialize FastLED + FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); + FastLED.setBrightness(gLedSettings.Led_Brightness); + FastLED.setDither(DISABLE_DITHER); + FastLED.setMaxRefreshRate(200); // limit LED refresh rate to 200Hz (less likely to cause flickering) - if (led_settings_changed) { - led_settings_changed = false; - // load led settings from NVS - Led_LoadSettings(gLedSettings); - // number of indicator/control leds changed - if (((gLedSettings.numIndicatorLeds + gLedSettings.numControlLeds) != (numIndicatorLeds + numControlLeds)) || (gLedSettings.numControlLeds != numControlLeds)) { - FastLED.clear(true); - numIndicatorLeds = gLedSettings.numIndicatorLeds; - numControlLeds = gLedSettings.numControlLeds; - delete (leds); - delete (indicator); - leds = new CRGB[numIndicatorLeds + numControlLeds]; - indicator = new CRGBSet(leds, numIndicatorLeds); - FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); + LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; + LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; + bool animationActive = false; + int32_t animationTimer = 0; + uint8_t ledSettingsChanged; + + for (;;) { + + if (xQueueReceive(gLedQueue, &ledSettingsChanged, 0) == pdPASS) { + // load led settings from NVS + Led_LoadSettings(gLedSettings); + // number of indicator/control leds changed + if (((gLedSettings.numIndicatorLeds + gLedSettings.numControlLeds) != (numIndicatorLeds + numControlLeds)) || (gLedSettings.numControlLeds != numControlLeds)) { + FastLED.clear(true); + numIndicatorLeds = gLedSettings.numIndicatorLeds; + numControlLeds = gLedSettings.numControlLeds; + delete (leds); + delete (indicator); + leds = new CRGB[numIndicatorLeds + numControlLeds]; + indicator = new CRGBSet(leds, numIndicatorLeds); + FastLED.addLeds(leds, numIndicatorLeds + numControlLeds).setCorrection(TypicalSMD5050); + } } - } - // special handling - if (gLedSettings.Led_Pause) { // Workaround to prevent exceptions while NVS-writes take place - return; - } + // special handling + if (gLedSettings.Led_Pause) { // Workaround to prevent exceptions while NVS-writes take place + vTaskDelay(portTICK_PERIOD_MS * 10); + continue; + } - Led_DrawControls(leds); - - bool startNewAnimation = false; - - // check indications and set led-mode - // this mode will then be animated if the priority and the current animation state fit - if (!LED_INDICATOR_IS_SET(LedIndicatorType::BootComplete)) { - nextAnimation = LedAnimationType::Boot; - } else if (CheckForPowerButtonAnimation()) { - nextAnimation = LedAnimationType::Shutdown; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Error)) { - LED_INDICATOR_CLEAR(LedIndicatorType::Error); - nextAnimation = LedAnimationType::Error; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Ok)) { - LED_INDICATOR_CLEAR(LedIndicatorType::Ok); - nextAnimation = LedAnimationType::Ok; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VoltageWarning)) { - LED_INDICATOR_CLEAR(LedIndicatorType::VoltageWarning); - nextAnimation = LedAnimationType::VoltageWarning; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Voltage)) { - nextAnimation = LedAnimationType::BatteryMeasurement; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VolumeChange)) { - nextAnimation = LedAnimationType::Volume; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Rewind)) { - LED_INDICATOR_CLEAR(LedIndicatorType::Rewind); - nextAnimation = LedAnimationType::Rewind; - } else if (LED_INDICATOR_IS_SET(LedIndicatorType::PlaylistProgress)) { - nextAnimation = LedAnimationType::Playlist; - } else if (gPlayProperties.currentSpeechActive) { - nextAnimation = LedAnimationType::Speech; - } else if (gPlayProperties.playlistFinished) { - nextAnimation = LedAnimationType::Idle; - } else if (gPlayProperties.pausePlay && !gPlayProperties.isWebstream) { - nextAnimation = LedAnimationType::Pause; - } else if ((gPlayProperties.playMode != BUSY) && (gPlayProperties.playMode != NO_PLAYLIST) && gPlayProperties.audioFileSize > 0) { // progress for a file/stream with known size - nextAnimation = LedAnimationType::Progress; - } else if (gPlayProperties.isWebstream) { // webstream animation (for streams with unknown size); pause animation is also handled by the webstream animation function - nextAnimation = LedAnimationType::Webstream; - } else if (gPlayProperties.playMode == NO_PLAYLIST) { - nextAnimation = LedAnimationType::Idle; - } else if (gPlayProperties.playMode == BUSY) { - nextAnimation = LedAnimationType::Busy; - } else { - nextAnimation = LedAnimationType::NoNewAnimation; // should not happen - } + Led_DrawControls(leds); + + uint32_t taskDelay = 20; + bool startNewAnimation = false; + + // check indications and set led-mode + // this mode will then be animated if the priority and the current animation state fit + if (!LED_INDICATOR_IS_SET(LedIndicatorType::BootComplete)) { + nextAnimation = LedAnimationType::Boot; + } else if (CheckForPowerButtonAnimation()) { + nextAnimation = LedAnimationType::Shutdown; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Error)) { + LED_INDICATOR_CLEAR(LedIndicatorType::Error); + nextAnimation = LedAnimationType::Error; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Ok)) { + LED_INDICATOR_CLEAR(LedIndicatorType::Ok); + nextAnimation = LedAnimationType::Ok; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VoltageWarning)) { + LED_INDICATOR_CLEAR(LedIndicatorType::VoltageWarning); + nextAnimation = LedAnimationType::VoltageWarning; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Voltage)) { + nextAnimation = LedAnimationType::BatteryMeasurement; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::VolumeChange)) { + nextAnimation = LedAnimationType::Volume; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::Rewind)) { + LED_INDICATOR_CLEAR(LedIndicatorType::Rewind); + nextAnimation = LedAnimationType::Rewind; + } else if (LED_INDICATOR_IS_SET(LedIndicatorType::PlaylistProgress)) { + nextAnimation = LedAnimationType::Playlist; + } else if (gPlayProperties.currentSpeechActive) { + nextAnimation = LedAnimationType::Speech; + } else if (gPlayProperties.playlistFinished) { + nextAnimation = LedAnimationType::Idle; + } else if (gPlayProperties.pausePlay && !gPlayProperties.isWebstream) { + nextAnimation = LedAnimationType::Pause; + } else if ((gPlayProperties.playMode != BUSY) && (gPlayProperties.playMode != NO_PLAYLIST) && gPlayProperties.audioFileSize > 0) { // progress for a file/stream with known size + nextAnimation = LedAnimationType::Progress; + } else if (gPlayProperties.isWebstream) { // webstream animation (for streams with unknown size); pause animation is also handled by the webstream animation function + nextAnimation = LedAnimationType::Webstream; + } else if (gPlayProperties.playMode == NO_PLAYLIST) { + nextAnimation = LedAnimationType::Idle; + } else if (gPlayProperties.playMode == BUSY) { + nextAnimation = LedAnimationType::Busy; + } else { + nextAnimation = LedAnimationType::NoNewAnimation; // should not happen + } - // check for instant transition if the requested animation has a higher priority then the current one - if (nextAnimation < activeAnimation) { - animationActive = false; // abort current animation - animationTimer = 0; - } - // transition to new animation - if ((!animationActive) && (animationTimer <= 0)) { - activeAnimation = nextAnimation; // set new animation - startNewAnimation = true; - } + // check for instant transition if the requested animation has a higher priority then the current one + if (nextAnimation < activeAnimation) { + animationActive = false; // abort current animation + animationTimer = 0; + } + // transition to new animation + if ((!animationActive) && (animationTimer <= 0)) { + activeAnimation = nextAnimation; // set new animation + startNewAnimation = true; + } - // apply brightness-changes - if (lastLedBrightness != gLedSettings.Led_Brightness) { - FastLED.setBrightness(gLedSettings.Led_Brightness); - lastLedBrightness = gLedSettings.Led_Brightness; - } + // apply brightness-changes + if (lastLedBrightness != gLedSettings.Led_Brightness) { + FastLED.setBrightness(gLedSettings.Led_Brightness); + lastLedBrightness = gLedSettings.Led_Brightness; + } - // when there is no delay anymore we have to animate something - if (animationTimer <= 0) { - AnimationReturnType ret; - // animate the current animation - switch (activeAnimation) { - case LedAnimationType::Boot: - ret = Animation_Boot(startNewAnimation, *indicator); - break; - - case LedAnimationType::Shutdown: - ret = Animation_Shutdown(startNewAnimation, *indicator); - break; - - case LedAnimationType::Error: - ret = Animation_Error(startNewAnimation, *indicator); - break; - - case LedAnimationType::Ok: - ret = Animation_Ok(startNewAnimation, *indicator); - break; - - case LedAnimationType::Volume: - ret = Animation_Volume(startNewAnimation, *indicator); - break; - - case LedAnimationType::VoltageWarning: - ret = Animation_VoltageWarning(startNewAnimation, *indicator); - break; - - case LedAnimationType::BatteryMeasurement: - ret = Animation_BatteryMeasurement(startNewAnimation, *indicator); - break; - - case LedAnimationType::Rewind: - ret = Animation_Rewind(startNewAnimation, *indicator); - break; - - case LedAnimationType::Playlist: - ret = Animation_PlaylistProgress(startNewAnimation, *indicator); - break; - - case LedAnimationType::Idle: - ret = Animation_Idle(startNewAnimation, *indicator); - break; - - case LedAnimationType::Busy: - ret = Animation_Busy(startNewAnimation, *indicator); - break; - - case LedAnimationType::Speech: - ret = Animation_Speech(startNewAnimation, *indicator); - break; - - case LedAnimationType::Pause: - ret = Animation_Pause(startNewAnimation, *indicator); - break; - - case LedAnimationType::Progress: - ret = Animation_Progress(startNewAnimation, *indicator); - break; - - case LedAnimationType::Webstream: - ret = Animation_Webstream(startNewAnimation, *indicator); - break; - - default: - *indicator = CRGB::Black; + // when there is no delay anymore we have to animate something + if (animationTimer <= 0) { + AnimationReturnType ret; + // animate the current animation + switch (activeAnimation) { + case LedAnimationType::Boot: + ret = Animation_Boot(startNewAnimation, *indicator); + break; + + case LedAnimationType::Shutdown: + ret = Animation_Shutdown(startNewAnimation, *indicator); + break; + + case LedAnimationType::Error: + ret = Animation_Error(startNewAnimation, *indicator); + break; + + case LedAnimationType::Ok: + ret = Animation_Ok(startNewAnimation, *indicator); + break; + + case LedAnimationType::Volume: + ret = Animation_Volume(startNewAnimation, *indicator); + break; + + case LedAnimationType::VoltageWarning: + ret = Animation_VoltageWarning(startNewAnimation, *indicator); + break; + + case LedAnimationType::BatteryMeasurement: + ret = Animation_BatteryMeasurement(startNewAnimation, *indicator); + break; + + case LedAnimationType::Rewind: + ret = Animation_Rewind(startNewAnimation, *indicator); + break; + + case LedAnimationType::Playlist: + ret = Animation_PlaylistProgress(startNewAnimation, *indicator); + break; + + case LedAnimationType::Idle: + ret = Animation_Idle(startNewAnimation, *indicator); + break; + + case LedAnimationType::Busy: + ret = Animation_Busy(startNewAnimation, *indicator); + break; + + case LedAnimationType::Speech: + ret = Animation_Speech(startNewAnimation, *indicator); + break; + + case LedAnimationType::Pause: + ret = Animation_Pause(startNewAnimation, *indicator); + break; + + case LedAnimationType::Progress: + ret = Animation_Progress(startNewAnimation, *indicator); + break; + + case LedAnimationType::Webstream: + ret = Animation_Webstream(startNewAnimation, *indicator); + break; + + default: + *indicator = CRGB::Black; + FastLED.show(); + ret.animationActive = false; + ret.animationDelay = 50; + break; + } + // apply delay and state from animation + animationActive = ret.animationActive; + animationTimer = ret.animationDelay; + if (ret.animationRefresh) { FastLED.show(); - ret.animationActive = false; - ret.animationDelay = 50; - break; - } - // apply delay and state from animation - animationActive = ret.animationActive; - animationTimer = ret.animationDelay; - animationStartTimestamp = millis(); - if (ret.animationRefresh) { - FastLED.show(); + } } - } - // don't do anything else, until time is up - if (((millis() - animationStartTimestamp) >= animationTimer)) { - // we have to wait for the next animation - animationTimer = 0; + // get the time to wait and delay the task + if ((animationTimer > 0) && (animationTimer < taskDelay)) { + taskDelay = animationTimer; + if (taskDelay < 5) { + taskDelay = 5; // minimum delay + } + } + animationTimer -= taskDelay; + vTaskDelay(portTICK_PERIOD_MS * taskDelay); } + delete (leds); + delete (indicator); + vTaskDelete(NULL); } #endif @@ -1215,13 +1236,13 @@ AnimationReturnType Animation_BatteryMeasurement(const bool startNewAnimation, C void Led_TaskPause(void) { #ifdef NEOPIXEL_ENABLE - leds_active = false; + vTaskSuspend(Led_TaskHandle); FastLED.clear(true); #endif } void Led_TaskResume(void) { #ifdef NEOPIXEL_ENABLE - leds_active = true; + vTaskResume(Led_TaskHandle); #endif } diff --git a/src/Led.h b/src/Led.h index dbe36f1f..07985727 100644 --- a/src/Led.h +++ b/src/Led.h @@ -62,12 +62,9 @@ struct AnimationReturnType { #define LED_INITIAL_BRIGHTNESS 16u #define LED_INITIAL_NIGHT_BRIGHTNESS 2u -// #define FASTLED_WS2812_T1 250 // original 250 -// #define FASTLED_WS2812_T2 625 // original 625 -// #define FASTLED_WS2812_T3 375 // original 375 -// #define FASTLED_ALLOW_INTERRUPTS 0 -// #define FASTLED_LED_OVERCLOCK 1.0f // original 1.0f -// #define FASTLED_ESP32_USE_CLOCKLESS_SPI 1 +// #define FASTLED_WS2812_T1 350 // original 250 - changed +// #define FASTLED_WS2812_T2 700 // original 625 - changed +// #define FASTLED_WS2812_T3 150 // original 375 - changed #include @@ -100,7 +97,6 @@ uint8_t Led_GetBrightness(void); void Led_SetBrightness(uint8_t value); void Led_TaskPause(void); void Led_TaskResume(void); -void Led_Cyclic(void); void Led_SetNightmode(bool enabled); bool Led_GetNightmode(); diff --git a/src/Queues.cpp b/src/Queues.cpp index 33cdada9..14352570 100644 --- a/src/Queues.cpp +++ b/src/Queues.cpp @@ -6,6 +6,7 @@ #include "Rfid.h" QueueHandle_t gRfidCardQueue; +QueueHandle_t gLedQueue; void Queues_Init(void) { // Create queues @@ -14,4 +15,9 @@ void Queues_Init(void) { if (gRfidCardQueue == NULL) { Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Rfid"); } + + gLedQueue = xQueueCreate(1, sizeof(uint8_t)); + if (gLedQueue == NULL) { + Log_Printf(LOGLEVEL_ERROR, unableToCreateQueue, "Led"); + } } diff --git a/src/Queues.h b/src/Queues.h index 6425ea09..c6597621 100644 --- a/src/Queues.h +++ b/src/Queues.h @@ -1,5 +1,6 @@ #pragma once extern QueueHandle_t gRfidCardQueue; +extern QueueHandle_t gLedQueue; void Queues_Init(void); diff --git a/src/main.cpp b/src/main.cpp index f137b5a1..e3f3da27 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,7 +151,9 @@ void setup() { // All checks that could send us to sleep are done, power up fully Power_PeripheralOn(); - Led_Init(); + // Init moved to start of cyclic-task, to be executed on the same core-context as the task. + // Workaround for a bug in old RMT-driver of LED-strip-lib (from FastLED) + // Led_Init(); // Needs power first SdCard_Init(); @@ -217,6 +219,13 @@ void setup() { } void loop() { + // Init in Core-1-context to avoid issues with LED-strip lib (FastLED) and RMT-driver + static bool first_time = true; + if (first_time) { + Led_Init(); + first_time = false; + } + if (OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) { // bluetooth speaker mode Bluetooth_Cyclic(); @@ -232,7 +241,6 @@ void loop() { RotaryEncoder_Cyclic(); } AudioPlayer_Cyclic(); - Led_Cyclic(); Battery_Cyclic(); Button_Cyclic(); System_Cyclic(); From 45f900d24a250f29ef893a1d0fc602ef99cfc319 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Sat, 24 May 2025 20:05:27 +0200 Subject: [PATCH 20/27] speedup web again. pausing Led-task can cause exceptions --- platformio.ini | 5 ++--- src/Web.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index a163ad53..56e96829 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,8 +33,7 @@ lib_deps = https://github.com/schreibfaul1/ESP32-audioI2S.git#c694298 ; v3.2.0 + bugfix setpos (18.05.2025) https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f - ;https://github.com/FastLED/FastLED.git#b0f1447 ; v3.9.16 - https://github.com/Joe91/FastLED.git#3ab1e7e ; v3.9.16 (fork) + https://github.com/FastLED/FastLED.git#d134295 ; v3.9.16+ https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 @@ -54,7 +53,7 @@ board_build.embed_txtfiles = managed_components/espressif__esp_rainmaker/server_certs/rmaker_ota_server.crt build_flags = - -DCONFIG_ASYNC_TCP_RUNNING_CORE=0 + -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 -DCONFIG_ASYNC_TCP_USE_WDT=1 ; -DCORE_DEBUG_LEVEL=6 -std=c++17 diff --git a/src/Web.cpp b/src/Web.cpp index 931bf19b..8e4553f5 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -442,7 +442,7 @@ void webserverStart(void) { if (!index) { // pause some tasks to get more free CPU time for the upload - // Audio_TaskPause(); + Audio_TaskPause(); // Led_TaskPause(); Rfid_TaskPause(); Update.begin(); @@ -456,7 +456,7 @@ void webserverStart(void) { Update.end(true); // resume the paused tasks // Led_TaskResume(); - // Audio_TaskResume(); + Audio_TaskResume(); Rfid_TaskResume(); Log_Println(fwEnd, LOGLEVEL_NOTICE); if (Update.hasError()) { @@ -1639,7 +1639,7 @@ void explorerHandleFileStorageTask(void *parameter) { uploadFile.setBufferSize(chunk_size); // pause some tasks to get more free CPU time for the upload - // Audio_TaskPause(); + Audio_TaskPause(); // Led_TaskPause(); Rfid_TaskPause(); @@ -1678,7 +1678,7 @@ void explorerHandleFileStorageTask(void *parameter) { free(parameter); // resume the paused tasks // Led_TaskResume(); - // Audio_TaskResume(); + Audio_TaskResume(); Rfid_TaskResume(); // destroy double buffer memory, since the upload was interrupted destroyDoubleBuffer(); @@ -1693,7 +1693,7 @@ void explorerHandleFileStorageTask(void *parameter) { free(parameter); // resume the paused tasks // Led_TaskResume(); - // Audio_TaskResume(); + Audio_TaskResume(); Rfid_TaskResume(); // send signal to upload function to terminate xSemaphoreGive(explorerFileUploadFinished); From 143943b1819f032ef73ddafb32582e62d2d2f51c Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 19 Jun 2025 19:56:08 +0200 Subject: [PATCH 21/27] finally working leds? --- platformio.ini | 3 ++- src/Led.cpp | 4 ++-- src/Led.h | 2 ++ src/main.cpp | 11 +---------- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/platformio.ini b/platformio.ini index 56e96829..c4ac71d5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,7 +33,8 @@ lib_deps = https://github.com/schreibfaul1/ESP32-audioI2S.git#c694298 ; v3.2.0 + bugfix setpos (18.05.2025) https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f - https://github.com/FastLED/FastLED.git#d134295 ; v3.9.16+ + ; https://github.com/FastLED/FastLED.git#971beb6 ; v3.10.0 + https://github.com/Joe91/FastLED#82f73089a ; v3.10.0 + spi-workaround https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 diff --git a/src/Led.cpp b/src/Led.cpp index 4b328562..019c39d6 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -152,11 +152,11 @@ void Led_Init(void) { xTaskCreatePinnedToCore( Led_Task, /* Function to implement the task */ "Led_Task", /* Name of the task */ - 2048, /* Stack size in words */ + 4096, /* Stack size in words */ NULL, /* Task input parameter */ 1, /* Priority of the task */ &Led_TaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ + 0 /* Core where the task should run */ ); #endif } diff --git a/src/Led.h b/src/Led.h index 07985727..078defc3 100644 --- a/src/Led.h +++ b/src/Led.h @@ -66,6 +66,8 @@ struct AnimationReturnType { // #define FASTLED_WS2812_T2 700 // original 625 - changed // #define FASTLED_WS2812_T3 150 // original 375 - changed + #define FASTLED_ESP32_USE_CLOCKLESS_SPI 1 + #include struct LedSettings { diff --git a/src/main.cpp b/src/main.cpp index e3f3da27..d1590728 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,9 +151,7 @@ void setup() { // All checks that could send us to sleep are done, power up fully Power_PeripheralOn(); - // Init moved to start of cyclic-task, to be executed on the same core-context as the task. - // Workaround for a bug in old RMT-driver of LED-strip-lib (from FastLED) - // Led_Init(); + Led_Init(); // Needs power first SdCard_Init(); @@ -219,13 +217,6 @@ void setup() { } void loop() { - // Init in Core-1-context to avoid issues with LED-strip lib (FastLED) and RMT-driver - static bool first_time = true; - if (first_time) { - Led_Init(); - first_time = false; - } - if (OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) { // bluetooth speaker mode Bluetooth_Cyclic(); From 1b8c822783c5a11cea33ef790ac33a60a4db3ba7 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 19 Jun 2025 20:11:56 +0200 Subject: [PATCH 22/27] update audio-lib, wait for wifi-connection for mqtt (no more errors on bootup) --- platformio.ini | 2 +- src/Led.cpp | 2 +- src/Mqtt.cpp | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index c4ac71d5..9d7daa2c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,7 +30,7 @@ extra_scripts = pre:updateSdkConfig.py pre:processHtml.py lib_deps = - https://github.com/schreibfaul1/ESP32-audioI2S.git#c694298 ; v3.2.0 + bugfix setpos (18.05.2025) + https://github.com/schreibfaul1/ESP32-audioI2S.git#0443b0d ; v3.3.2 https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f ; https://github.com/FastLED/FastLED.git#971beb6 ; v3.10.0 diff --git a/src/Led.cpp b/src/Led.cpp index 019c39d6..b7719d5d 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -152,7 +152,7 @@ void Led_Init(void) { xTaskCreatePinnedToCore( Led_Task, /* Function to implement the task */ "Led_Task", /* Name of the task */ - 4096, /* Stack size in words */ + 3072, /* Stack size in words */ NULL, /* Task input parameter */ 1, /* Priority of the task */ &Led_TaskHandle, /* Task handle. */ diff --git a/src/Mqtt.cpp b/src/Mqtt.cpp index 97c7a09a..31ac13a2 100644 --- a/src/Mqtt.cpp +++ b/src/Mqtt.cpp @@ -123,7 +123,7 @@ void Mqtt_Init() { mqtt_client = esp_mqtt_client_init(&mqtt_cfg); esp_mqtt_client_register_event(mqtt_client, esp_mqtt_event_id_t::MQTT_EVENT_ANY, mqtt_event_handler, NULL); - esp_mqtt_client_start(mqtt_client); + // don't start the task yet, wait for WiFi to be connected } #else @@ -133,7 +133,13 @@ void Mqtt_Init() { void Mqtt_OnWifiConnected(void) { #ifdef MQTT_ENABLE - esp_mqtt_client_reconnect(mqtt_client); + static bool mqtt_started = false; + if (!mqtt_started) { + esp_mqtt_client_start(mqtt_client); + mqtt_started = true; + } else { + esp_mqtt_client_reconnect(mqtt_client); + } #endif } From 32142f864cf7d0dd64b047885cc2119c961d22a3 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 19 Jun 2025 20:22:18 +0200 Subject: [PATCH 23/27] fix platformio.ini --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9d7daa2c..bba52711 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,7 +34,7 @@ lib_deps = https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib#554959f ; https://github.com/FastLED/FastLED.git#971beb6 ; v3.10.0 - https://github.com/Joe91/FastLED#82f73089a ; v3.10.0 + spi-workaround + https://github.com/Joe91/FastLED#82f7308 ; v3.10.0 + spi-workaround https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 From a93631f8d1520171a5ad1c67c7662ae45be08f53 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 19 Jun 2025 21:40:00 +0200 Subject: [PATCH 24/27] use .git --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index bba52711..5b339837 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,10 +32,10 @@ extra_scripts = lib_deps = https://github.com/schreibfaul1/ESP32-audioI2S.git#0443b0d ; v3.3.2 https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 - https://github.com/peterus/ESP-FTP-Server-Lib#554959f + https://github.com/peterus/ESP-FTP-Server-Lib.git#554959f ; https://github.com/FastLED/FastLED.git#971beb6 ; v3.10.0 - https://github.com/Joe91/FastLED#82f7308 ; v3.10.0 + spi-workaround - https://github.com/ESP32Async/ESPAsyncWebServer#1baee81 ; v3.7.7 + https://github.com/Joe91/FastLED.git#82f7308 ; v3.10.0 + spi-workaround + https://github.com/ESP32Async/ESPAsyncWebServer.git#1baee81 ; v3.7.7 https://github.com/bblanchon/ArduinoJson.git#3252013 ; v7.4.1 https://github.com/pschatzmann/arduino-audio-tools.git#c19fbd6 ; v1.0.2 https://github.com/pschatzmann/ESP32-A2DP.git#8faaafa ; v1.8.7 @@ -44,7 +44,7 @@ lib_deps = https://github.com/tueddy/rfid.git#caa3e6d ; avoid warnings, fork from https://github.com/miguelbalboa/rfid.git#0ff12a1 https://github.com/tuniii/LogRingBuffer.git#89d7d3e https://github.com/tueddy/PN5180-Library.git#e6449a9 ;v2.3.5 - https://github.com/SZenglein/Arduino-MAX17055_Driver#75cdfcf + https://github.com/SZenglein/Arduino-MAX17055_Driver.git#75cdfcf https://github.com/tueddy/natsort.git#ebbf660 ; avoid warnings, fork from https://github.com/sourcefrog/natsort.git#cdd8df9 board_build.embed_txtfiles = From fd99cded6aba5bcc869151eb4914182a9e4eff7e Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Tue, 24 Jun 2025 19:50:13 +0200 Subject: [PATCH 25/27] add pausePlayState to mqtt --- src/AudioPlayer.cpp | 8 ++++++++ src/Mqtt.cpp | 1 + src/settings.h | 1 + 3 files changed, 10 insertions(+) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index ff9726fa..6361cba4 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -461,6 +461,7 @@ void AudioPlayer_Loop() { gPlayProperties.trackFinished = false; gPlayProperties.playlistFinished = false; #ifdef MQTT_ENABLE + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); publishMqtt(topicPlaymodeState, static_cast(gPlayProperties.playMode), false); publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); #endif @@ -517,6 +518,8 @@ void AudioPlayer_Loop() { gPlayProperties.playMode = NO_PLAYLIST; Audio_setTitle(noPlaylist); AudioPlayer_ClearCover(); + + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); return; case PAUSEPLAY: @@ -532,6 +535,7 @@ void AudioPlayer_Loop() { AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), audio->getFilePos() - audio->inBufferFilled(), gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); } gPlayProperties.pausePlay = !gPlayProperties.pausePlay; + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); Web_SendWebsocketData(0, WebsocketCodeType::TrackInfo); return; @@ -540,6 +544,7 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); } if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed gPlayProperties.repeatCurrentTrack = false; @@ -575,6 +580,7 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); } if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed gPlayProperties.repeatCurrentTrack = false; @@ -636,6 +642,7 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); } gPlayProperties.currentTrackNumber = 0; if (gPlayProperties.saveLastPlayPosition) { @@ -653,6 +660,7 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); } if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) { gPlayProperties.currentTrackNumber = gPlayProperties.playlist->size() - 1; diff --git a/src/Mqtt.cpp b/src/Mqtt.cpp index 01f6e54f..dd30bdef 100644 --- a/src/Mqtt.cpp +++ b/src/Mqtt.cpp @@ -267,6 +267,7 @@ void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event publishMqtt(topicSleepTimerState, System_GetSleepTimerTimeStamp(), false); publishMqtt(topicLockControlsState, static_cast(System_AreControlsLocked()), false); publishMqtt(topicPlaymodeState, static_cast(gPlayProperties.playMode), false); + publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); publishMqtt(topicLedBrightnessState, static_cast(Led_GetBrightness()), false); publishMqtt(topicCurrentIPv4IP, Wlan_GetIpAddress().c_str(), false); publishMqtt(topicRepeatModeState, static_cast(AudioPlayer_GetRepeatMode()), false); diff --git a/src/settings.h b/src/settings.h index 303c06be..90bb8ce5 100644 --- a/src/settings.h +++ b/src/settings.h @@ -284,6 +284,7 @@ constexpr const char topicState[] = "State"; constexpr const char topicCurrentIPv4IP[] = "IPv4"; constexpr const char topicLockControlsState[] ="LockControls"; + constexpr const char topicPausePlayState[] = "PausePlay"; constexpr const char topicPlaymodeState[] = "Playmode"; constexpr const char topicRepeatModeState[] = "RepeatMode"; constexpr const char topicLedBrightnessState[] = "LedBrightness"; From db92f2c1cfa12d20a0e03deb52d741569add8762 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Tue, 24 Jun 2025 20:04:25 +0200 Subject: [PATCH 26/27] fix encapsulation of mqtt --- src/AudioPlayer.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 6361cba4..eb59c835 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -518,8 +518,9 @@ void AudioPlayer_Loop() { gPlayProperties.playMode = NO_PLAYLIST; Audio_setTitle(noPlaylist); AudioPlayer_ClearCover(); - +#ifdef MQTT_ENABLE publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); +#endif return; case PAUSEPLAY: @@ -535,7 +536,9 @@ void AudioPlayer_Loop() { AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, gPlayProperties.playlist->at(gPlayProperties.currentTrackNumber), audio->getFilePos() - audio->inBufferFilled(), gPlayProperties.playMode, gPlayProperties.currentTrackNumber, gPlayProperties.playlist->size()); } gPlayProperties.pausePlay = !gPlayProperties.pausePlay; +#ifdef MQTT_ENABLE publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); +#endif Web_SendWebsocketData(0, WebsocketCodeType::TrackInfo); return; @@ -544,7 +547,9 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; +#ifdef MQTT_ENABLE publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); +#endif } if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed gPlayProperties.repeatCurrentTrack = false; @@ -580,7 +585,9 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; +#ifdef MQTT_ENABLE publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); +#endif } if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed gPlayProperties.repeatCurrentTrack = false; @@ -642,7 +649,9 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; +#ifdef MQTT_ENABLE publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); +#endif } gPlayProperties.currentTrackNumber = 0; if (gPlayProperties.saveLastPlayPosition) { @@ -660,7 +669,9 @@ void AudioPlayer_Loop() { if (gPlayProperties.pausePlay) { audio->pauseResume(); gPlayProperties.pausePlay = false; +#ifdef MQTT_ENABLE publishMqtt(topicPausePlayState, static_cast(gPlayProperties.pausePlay), false); +#endif } if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.playlist->size()) { gPlayProperties.currentTrackNumber = gPlayProperties.playlist->size() - 1; From cb8df5709ef77f3cfc516ee190f9d8575f6a7655 Mon Sep 17 00:00:00 2001 From: Joe <1015.5@gmx.de> Date: Thu, 26 Jun 2025 06:42:39 +0200 Subject: [PATCH 27/27] fix: revert audio-lib because of issues on large files --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 5b339837..d90170f4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,7 +30,7 @@ extra_scripts = pre:updateSdkConfig.py pre:processHtml.py lib_deps = - https://github.com/schreibfaul1/ESP32-audioI2S.git#0443b0d ; v3.3.2 + https://github.com/schreibfaul1/ESP32-audioI2S.git#c694298 ; v3.2.0 + bugfix setpos (18.05.2025) https://github.com/madhephaestus/ESP32Encoder.git#2c986e0 https://github.com/peterus/ESP-FTP-Server-Lib.git#554959f ; https://github.com/FastLED/FastLED.git#971beb6 ; v3.10.0