diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..6647c181 --- /dev/null +++ b/.clang-format @@ -0,0 +1,41 @@ +--- +BasedOnStyle: WebKit +AlignArrayOfStructures: Right +AlignConsecutiveBitFields: + Enabled: true +AlignConsecutiveMacros: + Enabled: true +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +BreakBeforeBraces: Attach +Cpp11BracedListStyle: true +FixNamespaceComments: true +IncludeBlocks: Regroup +IncludeCategories: + - Regex: Arduino.h + Priority: -1 + SortPriority: -2 + CaseSensitive: true + - Regex: settings.h + Priority: -1 + SortPriority: -1 + CaseSensitive: true + - Regex: ^" + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: .* + Priority: 4 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: (_test)?$ +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +InsertBraces: true +InsertNewlineAtEOF: true +NamespaceIndentation: None +PointerAlignment: Right +SpaceAfterCStyleCast: true +Standard: Auto +TabWidth: 4 +UseTab: Always diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..d8566d6b --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# +# This file lists commit hashes for commits that should be ignored when +# using "git blame". This allows to hide major code reworks like formatting +# changes from the "git blame" history. +# diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 00000000..c78c54fd --- /dev/null +++ b/.gitconfig @@ -0,0 +1,2 @@ +[blame] + ignoreRevsFile = .git-blame-ignore-revs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 76364ae0..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Build all boards -on: - push: - -jobs: - main: - name: Build all boards - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Setup Python - uses: actions/setup-python@master - with: - python-version: '3.x' - - name: Install Platform IO - run: | - python -m pip install --upgrade pip - pip3 install -U setuptools platformio - - name: Build - run: platformio run -e esp32-a1s -e lolin32 -e lolin_d32 -e lolin_d32_pro -e lolin_d32_pro_sdmmc_pe -e nodemcu-32s -e az-delivery-devkit-v4 -e ttgo_t8 -e complete diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml new file mode 100644 index 00000000..5079a26e --- /dev/null +++ b/.github/workflows/clang-format-check.yml @@ -0,0 +1,15 @@ +name: clang-format-check +run-name: Clang-format Check +on: [workflow_dispatch, push, pull_request] +jobs: + formatting-check: + name: Formatting Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run clang-format style check for C/C++/Protobuf programs. + uses: jidicula/clang-format-action@v4.11.0 + with: + clang-format-version: '16' + check-path: 'src' + fallback-style: 'LLVM' # optional \ No newline at end of file diff --git a/.github/workflows/test-builds.yml b/.github/workflows/test-builds.yml new file mode 100644 index 00000000..c297f61a --- /dev/null +++ b/.github/workflows/test-builds.yml @@ -0,0 +1,58 @@ +name: build-all +run-name: Build all boards +on: + workflow_dispatch: + push: + pull_request: + paths: + - 'src/*' + - 'html/*' + - 'test/*' + - '**.ini' + - '**.py' + - '**.csv' + +jobs: + test_builds: + name: Run all Tests + runs-on: ubuntu-latest + strategy: + matrix: + variant: + - esp32-a1s + - lolin32 + - lolin_d32 + - lolin_d32_pro + - lolin_d32_pro_sdmmc_pe + - nodemcu-32s + - az-delivery-devkit-v4 + - ttgo_t8 + - complete + + steps: + - uses: actions/checkout@v3 + - name: Cache pip + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache PlatformIO + uses: actions/cache@v3 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + + - name: Setup Python 3.9 + uses: actions/setup-python@v4 + with: + python-version: '3.9' + - name: Install PlatformIO Core + run: | + pip install -U setuptools platformio + pio upgrade --dev + pio pkg update --global + - name: Build ${{ matrix.variant }} + run: platformio run -e ${{ matrix.variant }} diff --git a/.vscode/settings.json b/.vscode/settings.json index cad7657d..991b45ab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { - "cmake.configureOnOpen": false -} \ No newline at end of file + "cmake.configureOnOpen": false, + "editor.tabSize": 4, + "gitlens.advanced.blame.customArguments": [ + "--ignore-revs-file", ".git-blame-ignore-revs" + ] +} diff --git a/README.md b/README.md index 066fc266..cb6cc85a 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ to (re-)enable/disable WiFi: ESPuino can be used as Bluetooth sink (A2DP sink). In this mode you can stream audio (e.g. from a mobile device) via Bluetooth to your ESPuino. This mode can be enabled/disabled via a RFID modification card or by assigning action `CMD_TOGGLE_BLUETOOTH_MODE` to a button (or multi-button). -Applying this will restart ESPuino immediately. Activated Bluetooth is indicated by four +Applying this will restart ESPuino immediately. Activated Bluetooth is indicated by four slow rotating _blue-violet_ LEDs. After the Bluetooth device is paired the LEDs turn to blue. ### ESPuino as A2DP source (stream from ESPuino) @@ -486,3 +486,26 @@ described as follows. | topicBatterySOC | float | Current battery charge in percent (e.g. 83.0) | | topicWiFiRssiState | int | Numeric WiFi signal-strength (dBm) | | topicSRevisionState | String | Software-revision | + +## Development and Contributions + +### Code Formatting + +Automatic code formatting via `clang-format` is used. The configuration/rules can be found in +`.clang-format`. If you use Visual Studio Code as IDE, the support for this is automatically +available through the C++ extension. + +When editing source code, use Ctrl+Shift+I to run the auto-formatting on the file or Ctrl+K Ctrl+F +for the selected code. + +See the [documentation](https://code.visualstudio.com/docs/cpp/cpp-ide#_code-formatting) for more +options like run auto-formatting on saving or editing the file. + +The CI (via "GitHub Actions") checks changes when they are pushed in order to keep the source code +clean and provide feedback to the developers and maintainers. + +To keep the output of `git blame` clean despite the massive changes when introducing new formatting +rules, we have a `.git-blame-ignore-revs` that lists the commits to ignore. In VSCode this should be +used automatically if you use the "GitLens" extension. Otherwise make sure you apply the config +fragment for git by running `git config --local include.path ../.gitconfig` once in your local +clone. diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp index 104227a9..888fe944 100644 --- a/src/AudioPlayer.cpp +++ b/src/AudioPlayer.cpp @@ -1,9 +1,11 @@ #include -#include -#include #include "settings.h" -#include "Audio.h" + #include "AudioPlayer.h" + +#include "Audio.h" +#include "Bluetooth.h" +#include "Cmd.h" #include "Common.h" #include "Led.h" #include "Log.h" @@ -15,19 +17,20 @@ #include "RotaryEncoder.h" #include "SdCard.h" #include "System.h" -#include "Wlan.h" #include "Web.h" -#include "Bluetooth.h" -#include "Cmd.h" +#include "Wlan.h" #include "main.h" -#define AUDIOPLAYER_VOLUME_MAX 21u -#define AUDIOPLAYER_VOLUME_MIN 0u +#include +#include + +#define AUDIOPLAYER_VOLUME_MAX 21u +#define AUDIOPLAYER_VOLUME_MIN 0u #define AUDIOPLAYER_VOLUME_INIT 3u playProps gPlayProperties; TaskHandle_t AudioTaskHandle; -//uint32_t cnt123 = 0; +// uint32_t cnt123 = 0; // Volume static uint8_t AudioPlayer_CurrentVolume = AUDIOPLAYER_VOLUME_INIT; @@ -41,9 +44,9 @@ time_t playTimeSecTotal = 0; time_t playTimeSecSinceStart = 0; #ifdef HEADPHONE_ADJUST_ENABLE - static bool AudioPlayer_HeadphoneLastDetectionState; - 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) +static bool AudioPlayer_HeadphoneLastDetectionState; +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); @@ -59,19 +62,19 @@ void AudioPlayer_Init(void) { // load playtime total from NVS playTimeSecTotal = gPrefsSettings.getULong("playTimeTotal", 0); - #ifndef USE_LAST_VOLUME_AFTER_REBOOT - // Get initial volume from NVS - uint32_t nvsInitialVolume = gPrefsSettings.getUInt("initVolume", 0); - #else - // Get volume used at last shutdown - uint32_t nvsInitialVolume = gPrefsSettings.getUInt("previousVolume", 999); - if (nvsInitialVolume == 999) { - gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetInitVolume()); - nvsInitialVolume = AudioPlayer_GetInitVolume(); - } else { - Log_Println(rememberLastVolume, LOGLEVEL_ERROR); - } - #endif +#ifndef USE_LAST_VOLUME_AFTER_REBOOT + // Get initial volume from NVS + uint32_t nvsInitialVolume = gPrefsSettings.getUInt("initVolume", 0); +#else + // Get volume used at last shutdown + uint32_t nvsInitialVolume = gPrefsSettings.getUInt("previousVolume", 999); + if (nvsInitialVolume == 999) { + gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetInitVolume()); + nvsInitialVolume = AudioPlayer_GetInitVolume(); + } else { + Log_Println(rememberLastVolume, LOGLEVEL_ERROR); + } +#endif if (nvsInitialVolume) { AudioPlayer_SetInitVolume(nvsInitialVolume); @@ -92,22 +95,22 @@ void AudioPlayer_Init(void) { Log_Println(wroteMaxLoudnessForSpeakerToNvs, LOGLEVEL_ERROR); } - #ifdef HEADPHONE_ADJUST_ENABLE - #if (HP_DETECT >= 0 && HP_DETECT <= MAX_GPIO) - pinMode(HP_DETECT, INPUT_PULLUP); - #endif - AudioPlayer_HeadphoneLastDetectionState = Audio_Detect_Mode_HP(Port_Read(HP_DETECT)); - - // Get maximum volume for headphone from NVS - uint32_t nvsAudioPlayer_MaxVolumeHeadphone = gPrefsSettings.getUInt("maxVolumeHp", 0); - if (nvsAudioPlayer_MaxVolumeHeadphone) { - AudioPlayer_MaxVolumeHeadphone = nvsAudioPlayer_MaxVolumeHeadphone; - Log_Printf(LOGLEVEL_INFO, restoredMaxLoudnessForHeadphoneFromNvs, nvsAudioPlayer_MaxVolumeHeadphone); - } else { - gPrefsSettings.putUInt("maxVolumeHp", nvsAudioPlayer_MaxVolumeHeadphone); - Log_Println(wroteMaxLoudnessForHeadphoneToNvs, LOGLEVEL_ERROR); - } +#ifdef HEADPHONE_ADJUST_ENABLE + #if (HP_DETECT >= 0 && HP_DETECT <= MAX_GPIO) + pinMode(HP_DETECT, INPUT_PULLUP); #endif + AudioPlayer_HeadphoneLastDetectionState = Audio_Detect_Mode_HP(Port_Read(HP_DETECT)); + + // Get maximum volume for headphone from NVS + uint32_t nvsAudioPlayer_MaxVolumeHeadphone = gPrefsSettings.getUInt("maxVolumeHp", 0); + if (nvsAudioPlayer_MaxVolumeHeadphone) { + AudioPlayer_MaxVolumeHeadphone = nvsAudioPlayer_MaxVolumeHeadphone; + Log_Printf(LOGLEVEL_INFO, restoredMaxLoudnessForHeadphoneFromNvs, nvsAudioPlayer_MaxVolumeHeadphone); + } else { + gPrefsSettings.putUInt("maxVolumeHp", nvsAudioPlayer_MaxVolumeHeadphone); + Log_Println(wroteMaxLoudnessForHeadphoneToNvs, LOGLEVEL_ERROR); + } +#endif // Adjust volume depending on headphone is connected and volume-adjustment is enabled AudioPlayer_SetupVolumeAndAmps(); @@ -118,13 +121,13 @@ void AudioPlayer_Init(void) { // 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 */ + 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 */ + &AudioTaskHandle, /* Task handle. */ + 1 /* Core where the task should run */ ); } } @@ -134,15 +137,15 @@ void AudioPlayer_Exit(void) { // save playtime total to NVS playTimeSecTotal += playTimeSecSinceStart; gPrefsSettings.putULong("playTimeTotal", playTimeSecTotal); - // Make sure last playposition for audiobook is saved when playback is active while shutdown was initiated - #ifdef SAVE_PLAYPOS_BEFORE_SHUTDOWN - if (!gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { - AudioPlayer_TrackControlToQueueSender(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); - } +// Make sure last playposition for audiobook is saved when playback is active while shutdown was initiated +#ifdef SAVE_PLAYPOS_BEFORE_SHUTDOWN + if (!gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { + AudioPlayer_TrackControlToQueueSender(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); } - #endif + } +#endif } static uint32_t lastPlayingTimestamp = 0; @@ -152,18 +155,18 @@ void AudioPlayer_Cyclic(void) { if ((millis() - lastPlayingTimestamp >= 1000) && gPlayProperties.playMode != NO_PLAYLIST && gPlayProperties.playMode != BUSY && !gPlayProperties.pausePlay) { // audio is playing, update the playtime since start lastPlayingTimestamp = millis(); - playTimeSecSinceStart+= 1; + playTimeSecSinceStart += 1; } } // Wrapper-function to reverse detection of connected headphones. // Normally headphones are supposed to be plugged in if a given GPIO/channel is LOW/false. bool Audio_Detect_Mode_HP(bool _state) { - #ifndef DETECT_HP_ON_HIGH - return _state; - #else - return !_state; - #endif +#ifndef DETECT_HP_ON_HIGH + return _state; +#else + return !_state; +#endif } uint8_t AudioPlayer_GetCurrentVolume(void) { @@ -218,103 +221,103 @@ void Audio_setTitle(const char *format, ...) { char buf[256]; va_list args; va_start(args, format); - vsnprintf(buf, sizeof(buf)/sizeof(buf[0]), format, args); + vsnprintf(buf, sizeof(buf) / sizeof(buf[0]), format, args); va_end(args); convertAsciiToUtf8(buf, gPlayProperties.title); // notify web ui and mqtt Web_SendWebsocketData(0, 30); - #ifdef MQTT_ENABLE - publishMqtt(topicTrackState, gPlayProperties.title, false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicTrackState, gPlayProperties.title, false); +#endif } // Set maxVolume depending on headphone-adjustment is enabled and headphone is/is not connected // Enable/disable PA/HP-amps initially void AudioPlayer_SetupVolumeAndAmps(void) { - #ifdef PLAY_MONO_SPEAKER - gPlayProperties.currentPlayMono = true; - gPlayProperties.newPlayMono = true; - #else - gPlayProperties.currentPlayMono = false; - gPlayProperties.newPlayMono = false; +#ifdef PLAY_MONO_SPEAKER + gPlayProperties.currentPlayMono = true; + gPlayProperties.newPlayMono = true; +#else + gPlayProperties.currentPlayMono = false; + gPlayProperties.newPlayMono = false; +#endif + +#ifndef HEADPHONE_ADJUST_ENABLE + AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker; + // If automatic HP-detection is not used, we enabled both (PA / HP) if defined + #ifdef GPIO_PA_EN + Port_Write(GPIO_PA_EN, true, true); + #endif + #ifdef GPIO_HP_EN + Port_Write(GPIO_HP_EN, true, true); + #endif +#else + if (Audio_Detect_Mode_HP(Port_Read(HP_DETECT))) { + AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker; // 1 if headphone is not connected + #ifdef GPIO_PA_EN + Port_Write(GPIO_PA_EN, true, true); + #endif + #ifdef GPIO_HP_EN + Port_Write(GPIO_HP_EN, false, true); #endif + } else { + AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeHeadphone; // 0 if headphone is connected (put to GND) + gPlayProperties.newPlayMono = false; // always stereo for headphones! - #ifndef HEADPHONE_ADJUST_ENABLE - AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker; - // If automatic HP-detection is not used, we enabled both (PA / HP) if defined - #ifdef GPIO_PA_EN - Port_Write(GPIO_PA_EN, true, true); - #endif - #ifdef GPIO_HP_EN - Port_Write(GPIO_HP_EN, true, true); - #endif - #else - if (Audio_Detect_Mode_HP(Port_Read(HP_DETECT))) { - AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker; // 1 if headphone is not connected - #ifdef GPIO_PA_EN - Port_Write(GPIO_PA_EN, true, true); - #endif - #ifdef GPIO_HP_EN - Port_Write(GPIO_HP_EN, false, true); - #endif - } else { - AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeHeadphone; // 0 if headphone is connected (put to GND) - gPlayProperties.newPlayMono = false; // always stereo for headphones! - - #ifdef GPIO_PA_EN - Port_Write(GPIO_PA_EN, false, true); - #endif - #ifdef GPIO_HP_EN - Port_Write(GPIO_HP_EN, true, true); - #endif - } - Log_Printf(LOGLEVEL_INFO, maxVolumeSet, AudioPlayer_MaxVolume); - return; + #ifdef GPIO_PA_EN + Port_Write(GPIO_PA_EN, false, true); + #endif + #ifdef GPIO_HP_EN + Port_Write(GPIO_HP_EN, true, true); #endif + } + Log_Printf(LOGLEVEL_INFO, maxVolumeSet, AudioPlayer_MaxVolume); + return; +#endif } void AudioPlayer_HeadphoneVolumeManager(void) { - #ifdef HEADPHONE_ADJUST_ENABLE - bool currentHeadPhoneDetectionState = Audio_Detect_Mode_HP(Port_Read(HP_DETECT)); - - if (AudioPlayer_HeadphoneLastDetectionState != currentHeadPhoneDetectionState && (millis() - AudioPlayer_HeadphoneLastDetectionTimestamp >= headphoneLastDetectionDebounce)) { - if (currentHeadPhoneDetectionState) { - AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker; - #ifdef PLAY_MONO_SPEAKER - gPlayProperties.newPlayMono = true; - #else - gPlayProperties.newPlayMono = false; - #endif - - #ifdef GPIO_PA_EN - Port_Write(GPIO_PA_EN, true, false); - #endif - #ifdef GPIO_HP_EN - Port_Write(GPIO_HP_EN, false, false); - #endif - } else { - 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 - } +#ifdef HEADPHONE_ADJUST_ENABLE + bool currentHeadPhoneDetectionState = Audio_Detect_Mode_HP(Port_Read(HP_DETECT)); + + if (AudioPlayer_HeadphoneLastDetectionState != currentHeadPhoneDetectionState && (millis() - AudioPlayer_HeadphoneLastDetectionTimestamp >= headphoneLastDetectionDebounce)) { + if (currentHeadPhoneDetectionState) { + AudioPlayer_MaxVolume = AudioPlayer_MaxVolumeSpeaker; + #ifdef PLAY_MONO_SPEAKER + gPlayProperties.newPlayMono = true; + #else + gPlayProperties.newPlayMono = false; + #endif - #ifdef GPIO_PA_EN - Port_Write(GPIO_PA_EN, false, false); - #endif - #ifdef GPIO_HP_EN - Port_Write(GPIO_HP_EN, true, false); - #endif + #ifdef GPIO_PA_EN + Port_Write(GPIO_PA_EN, true, false); + #endif + #ifdef GPIO_HP_EN + Port_Write(GPIO_HP_EN, false, false); + #endif + } else { + 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_HeadphoneLastDetectionState = currentHeadPhoneDetectionState; - AudioPlayer_HeadphoneLastDetectionTimestamp = millis(); - Log_Printf(LOGLEVEL_INFO, maxVolumeSet, AudioPlayer_MaxVolume); - } + + #ifdef GPIO_PA_EN + Port_Write(GPIO_PA_EN, false, false); + #endif + #ifdef GPIO_HP_EN + Port_Write(GPIO_HP_EN, true, false); #endif + } + AudioPlayer_HeadphoneLastDetectionState = currentHeadPhoneDetectionState; + AudioPlayer_HeadphoneLastDetectionTimestamp = millis(); + Log_Printf(LOGLEVEL_INFO, maxVolumeSet, AudioPlayer_MaxVolume); + } +#endif } -class AudioCustom: public Audio { +class AudioCustom : public Audio { public: void *operator new(size_t size) { return psramFound() ? ps_malloc(size) : malloc(size); @@ -323,21 +326,21 @@ class AudioCustom: public Audio { // 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 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 +#ifdef I2S_COMM_FMT_LSB_ENABLE + audio->setI2SCommFMT_LSB(true); +#endif uint8_t settleCount = 0; AudioPlayer_CurrentVolume = AudioPlayer_GetInitVolume(); audio->setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); - audio->setVolume(AudioPlayer_CurrentVolume,VOLUMECURVE); + audio->setVolume(AudioPlayer_CurrentVolume, VOLUMECURVE); audio->forceMono(gPlayProperties.currentPlayMono); if (gPlayProperties.currentPlayMono) { audio->setTone(3, 0, 0); @@ -356,11 +359,11 @@ void AudioPlayer_Task(void *parameter) { */ if (xQueueReceive(gVolumeQueue, ¤tVolume, 0) == pdPASS) { Log_Printf(LOGLEVEL_INFO, newLoudnessReceivedQueue, currentVolume); - audio->setVolume(currentVolume,VOLUMECURVE); + audio->setVolume(currentVolume, VOLUMECURVE); Web_SendWebsocketData(0, 50); - #ifdef MQTT_ENABLE - publishMqtt(topicLoudnessState, currentVolume, false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLoudnessState, currentVolume, false); +#endif } if (xQueueReceive(gTrackControlQueue, &trackCommand, 0) == pdPASS) { @@ -377,10 +380,10 @@ void AudioPlayer_Task(void *parameter) { Log_Printf(LOGLEVEL_NOTICE, newPlaylistReceived, gPlayProperties.numberOfTracks); Log_Printf(LOGLEVEL_DEBUG, "Free heap: %u", ESP.getFreeHeap()); - #ifdef MQTT_ENABLE - publishMqtt(topicPlaymodeState, gPlayProperties.playMode, false); - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicPlaymodeState, gPlayProperties.playMode, false); + publishMqtt(topicRepeatModeState, 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 @@ -395,8 +398,7 @@ void AudioPlayer_Task(void *parameter) { continue; } if (gPlayProperties.saveLastPlayPosition) { // Don't save for AUDIOBOOK_LOOP because not necessary - if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.numberOfTracks) - { + if (gPlayProperties.currentTrackNumber + 1 < gPlayProperties.numberOfTracks) { // Only save if there's another track, otherwise it will be saved at end of playlist anyway AudioPlayer_NvsRfidWriteWrapper(gPlayProperties.playRfidTag, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), 0, gPlayProperties.playMode, gPlayProperties.currentTrackNumber + 1, gPlayProperties.numberOfTracks); } @@ -414,7 +416,7 @@ void AudioPlayer_Task(void *parameter) { } 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) + 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(); @@ -459,9 +461,9 @@ void AudioPlayer_Task(void *parameter) { } if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed gPlayProperties.repeatCurrentTrack = false; - #ifdef MQTT_ENABLE - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicRepeatModeState, 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. @@ -494,9 +496,9 @@ void AudioPlayer_Task(void *parameter) { } if (gPlayProperties.repeatCurrentTrack) { // End loop if button was pressed gPlayProperties.repeatCurrentTrack = false; - #ifdef MQTT_ENABLE - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); +#endif } if (gPlayProperties.playMode == WEBSTREAM) { Log_Println(trackChangeWebstream, LOGLEVEL_INFO); @@ -514,7 +516,7 @@ void AudioPlayer_Task(void *parameter) { 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.numberOfTracks - 1; // Go back to last track in loop-mode when first track is played + gPlayProperties.currentTrackNumber = gPlayProperties.numberOfTracks - 1; // Go back to last track in loop-mode when first track is played } else { gPlayProperties.currentTrackNumber--; } @@ -618,9 +620,9 @@ void AudioPlayer_Task(void *parameter) { gPlayProperties.playMode = NO_PLAYLIST; Audio_setTitle(noPlaylist); AudioPlayer_ClearCover(); - #ifdef MQTT_ENABLE - publishMqtt(topicPlaymodeState, gPlayProperties.playMode, false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicPlaymodeState, gPlayProperties.playMode, false); +#endif gPlayProperties.currentTrackNumber = 0; gPlayProperties.numberOfTracks = 0; if (gPlayProperties.sleepAfterPlaylist) { @@ -681,19 +683,19 @@ void AudioPlayer_Task(void *parameter) { } if (gPlayProperties.isWebstream) { if (gPlayProperties.numberOfTracks > 1) { - Audio_setTitle("(%u/%u): Webradio", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks); + Audio_setTitle("(%u/%u): Webradio", gPlayProperties.currentTrackNumber + 1, gPlayProperties.numberOfTracks); } else { Audio_setTitle("Webradio"); } } else { if (gPlayProperties.numberOfTracks > 1) { - Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber)); + Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber + 1, gPlayProperties.numberOfTracks, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber)); } else { Audio_setTitle("%s", *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber)); } } AudioPlayer_ClearCover(); - Log_Printf(LOGLEVEL_NOTICE, currentlyPlaying, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks); + Log_Printf(LOGLEVEL_NOTICE, currentlyPlaying, *(gPlayProperties.playlist + gPlayProperties.currentTrackNumber), (gPlayProperties.currentTrackNumber + 1), gPlayProperties.numberOfTracks); gPlayProperties.playlistFinished = false; } } @@ -721,13 +723,13 @@ void AudioPlayer_Task(void *parameter) { gPlayProperties.tellMode = TTS_NONE; String ipText = Wlan_GetIpAddress(); bool speechOk; - #if (LANGUAGE == DE) - ipText.replace(".", "Punkt"); // make IP as text (replace thousand separator) - speechOk = audio->connecttospeech(ipText.c_str(), "de"); - #else - ipText.replace(".", "point"); - speechOk = audio->connecttospeech(ipText.c_str(), "en"); - #endif +#if (LANGUAGE == DE) + ipText.replace(".", "Punkt"); // make IP as text (replace thousand separator) + speechOk = audio->connecttospeech(ipText.c_str(), "de"); +#else + ipText.replace(".", "point"); + speechOk = audio->connecttospeech(ipText.c_str(), "en"); +#endif if (!speechOk) { System_IndicateError(); } @@ -740,17 +742,17 @@ void AudioPlayer_Task(void *parameter) { 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 { - snprintf(timeStringBuff, sizeof(timeStringBuff), "It is %02d:%02d AM", timeinfo.tm_hour, timeinfo.tm_min); - } - speechOk = audio->connecttospeech(timeStringBuff, "en"); - #endif +#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 { + 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(); } @@ -760,7 +762,7 @@ void AudioPlayer_Task(void *parameter) { 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 + xQueueSend(gRfidCardQueue, gPlayProperties.playRfidTag, 0); // Re-inject previous RFID-ID in order to continue playback } } @@ -779,9 +781,9 @@ void AudioPlayer_Task(void *parameter) { // Calculate relative position in file (for neopixel) for SD-card-mode if (!gPlayProperties.playlistFinished && !gPlayProperties.isWebstream) { - if (millis() % 20 == 0) { // Keep it simple - if (!gPlayProperties.pausePlay && (audio->getFileSize() > 0)) { // To progress necessary when paused - gPlayProperties.currentRelPos = ((double)(audio->getFilePos() - audio->inBufferFilled()) / (double)audio->getFileSize()) * 100; + if (millis() % 20 == 0) { // Keep it simple + if (!gPlayProperties.pausePlay && (audio->getFileSize() > 0)) { // To progress necessary when paused + gPlayProperties.currentRelPos = ((double) (audio->getFilePos() - audio->inBufferFilled()) / (double) audio->getFileSize()) * 100; } } } else { @@ -814,19 +816,19 @@ void AudioPlayer_Task(void *parameter) { } else { vTaskDelay(portTICK_PERIOD_MS * 1); } - //esp_task_wdt_reset(); // Don't forget to feed the dog! - - #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE - static uint8_t resetOnNextIdle = false; - if (gPlayProperties.playlistFinished || gPlayProperties.playMode == NO_PLAYLIST) { - if (resetOnNextIdle) { - Rfid_ResetOldRfid(); - resetOnNextIdle = false; - } - } else { - resetOnNextIdle = true; + // esp_task_wdt_reset(); // Don't forget to feed the dog! + +#ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE + static uint8_t resetOnNextIdle = false; + if (gPlayProperties.playlistFinished || gPlayProperties.playMode == NO_PLAYLIST) { + if (resetOnNextIdle) { + Rfid_ResetOldRfid(); + resetOnNextIdle = false; } - #endif + } else { + resetOnNextIdle = true; + } +#endif } vTaskDelete(NULL); } @@ -839,7 +841,7 @@ uint8_t AudioPlayer_GetRepeatMode(void) { return PLAYLIST; } else if (!gPlayProperties.repeatPlaylist && gPlayProperties.repeatCurrentTrack) { return TRACK; - } else{ + } else { return NO_REPEAT; } } @@ -868,45 +870,43 @@ void AudioPlayer_VolumeToQueueSender(const int32_t _newVolume, bool reAdjustRota } } - // Pauses playback if playback is active and volume is changes from minVolume+1 to minVolume (usually 0) void AudioPlayer_PauseOnMinVolume(const uint8_t oldVolume, const uint8_t newVolume) { - #ifdef PAUSE_ON_MIN_VOLUME - if (gPlayProperties.playMode == BUSY || gPlayProperties.playMode == NO_PLAYLIST) { - return; - } +#ifdef PAUSE_ON_MIN_VOLUME + if (gPlayProperties.playMode == BUSY || gPlayProperties.playMode == NO_PLAYLIST) { + return; + } - if (!gPlayProperties.pausePlay ) { // Volume changes from 1 to 0 - if (oldVolume == AudioPlayer_GetMinVolume()+1 && newVolume == AudioPlayer_GetMinVolume()) { - Cmd_Action(CMD_PLAYPAUSE); - } + if (!gPlayProperties.pausePlay) { // Volume changes from 1 to 0 + if (oldVolume == AudioPlayer_GetMinVolume() + 1 && newVolume == AudioPlayer_GetMinVolume()) { + Cmd_Action(CMD_PLAYPAUSE); } - if (gPlayProperties.pausePlay) { // Volume changes from 0 to 1 - if (oldVolume == AudioPlayer_GetMinVolume() && newVolume > AudioPlayer_GetMinVolume()) { - Cmd_Action(CMD_PLAYPAUSE); - } + } + if (gPlayProperties.pausePlay) { // Volume changes from 0 to 1 + if (oldVolume == AudioPlayer_GetMinVolume() && newVolume > AudioPlayer_GetMinVolume()) { + Cmd_Action(CMD_PLAYPAUSE); } - #endif + } +#endif } - // 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) { - // Make sure last playposition for audiobook is saved when new RFID-tag is applied - #ifdef SAVE_PLAYPOS_WHEN_RFID_CHANGE - if (!gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { - AudioPlayer_TrackControlToQueueSender(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); - } +// Make sure last playposition for audiobook is saved when new RFID-tag is applied +#ifdef SAVE_PLAYPOS_WHEN_RFID_CHANGE + if (!gPlayProperties.pausePlay && (gPlayProperties.playMode == AUDIOBOOK || gPlayProperties.playMode == AUDIOBOOK_LOOP)) { + AudioPlayer_TrackControlToQueueSender(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); } - #endif + } +#endif char filename[255]; - size_t sizeCpy = strnlen(_itemToPlay, sizeof(filename) - 1); // get the len of the play item (to a max of 254 chars) + size_t sizeCpy = strnlen(_itemToPlay, sizeof(filename) - 1); // get the len of the play item (to a max of 254 chars) memcpy(filename, _itemToPlay, sizeCpy); - filename[sizeCpy] = '\0'; // terminate the string + filename[sizeCpy] = '\0'; // terminate the string gPlayProperties.startAtFilePos = _lastPlayPos; gPlayProperties.currentTrackNumber = _trackLastPlayed; @@ -914,11 +914,11 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l if (_playMode != WEBSTREAM) { if (_playMode == RANDOM_SUBDIRECTORY_OF_DIRECTORY || _playMode == RANDOM_SUBDIRECTORY_OF_DIRECTORY_ALL_TRACKS_OF_DIR_RANDOM) { - const char *tmp = SdCard_pickRandomSubdirectory(filename); // *filename (input): target-directory // *filename (output): random subdirectory - if (tmp == NULL) { // If error occured while extracting random subdirectory + const char *tmp = SdCard_pickRandomSubdirectory(filename); // *filename (input): target-directory // *filename (output): random subdirectory + if (tmp == NULL) { // If error occured while extracting random subdirectory musicFiles = NULL; } else { - musicFiles = SdCard_ReturnPlaylist(filename, _playMode); // Provide random subdirectory in order to enter regular playlist-generation + musicFiles = SdCard_ReturnPlaylist(filename, _playMode); // Provide random subdirectory in order to enter regular playlist-generation } } else { musicFiles = SdCard_ReturnPlaylist(filename, _playMode); @@ -962,10 +962,10 @@ void AudioPlayer_TrackQueueDispatcher(const char *_itemToPlay, const uint32_t _l gPlayProperties.saveLastPlayPosition = false; gPlayProperties.playUntilTrackNumber = 0; - #ifdef PLAY_LAST_RFID_AFTER_REBOOT - // Store last RFID-tag to NVS - gPrefsSettings.putString("lastRfid", gCurrentRfidTagId); - #endif +#ifdef PLAY_LAST_RFID_AFTER_REBOOT + // Store last RFID-tag to NVS + gPrefsSettings.putString("lastRfid", gCurrentRfidTagId); +#endif switch (gPlayProperties.playMode) { case SINGLE_TRACK: { @@ -1148,7 +1148,7 @@ void AudioPlayer_RandomizePlaylist(char **str, const uint32_t count) { // Helper to sort playlist alphabetically static int AudioPlayer_ArrSortHelper(const void *a, const void *b) { - return strcmp(*(const char **)a, *(const char **)b); + return strcmp(*(const char **) a, *(const char **) b); } // Sort playlist alphabetically @@ -1161,9 +1161,9 @@ void AudioPlayer_ClearCover(void) { gPlayProperties.coverFilePos = 0; // websocket and mqtt notify cover image has changed Web_SendWebsocketData(0, 40); - #ifdef MQTT_ENABLE - publishMqtt(topicCoverChangedState, "", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicCoverChangedState, "", false); +#endif } // Some mp3-lib-stuff (slightly changed from default) @@ -1171,19 +1171,19 @@ void audio_info(const char *info) { Log_Printf(LOGLEVEL_INFO, "info : %s", info); } -void audio_id3data(const char *info) { //id3 metadata +void audio_id3data(const char *info) { // id3 metadata Log_Printf(LOGLEVEL_INFO, "id3data : %s", info); // get title - if (startsWith((char *)info, "Title:")) { + if (startsWith((char *) info, "Title:")) { if (gPlayProperties.numberOfTracks > 1) { - Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks, info + 6); + Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber + 1, gPlayProperties.numberOfTracks, info + 6); } else { Audio_setTitle("%s", info + 6); } } } -void audio_eof_mp3(const char *info) { //end of file +void audio_eof_mp3(const char *info) { // end of file Log_Printf(LOGLEVEL_INFO, "eof_mp3 : %s", info); gPlayProperties.trackFinished = true; } @@ -1192,7 +1192,7 @@ void audio_showstation(const char *info) { Log_Printf(LOGLEVEL_NOTICE, "station : %s", info); if (strcmp(info, "")) { if (gPlayProperties.numberOfTracks > 1) { - Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks, info); + Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber + 1, gPlayProperties.numberOfTracks, info); } else { Audio_setTitle("%s", info); } @@ -1203,7 +1203,7 @@ void audio_showstreamtitle(const char *info) { Log_Printf(LOGLEVEL_INFO, "streamtitle : %s", info); if (strcmp(info, "")) { if (gPlayProperties.numberOfTracks > 1) { - Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber+1, gPlayProperties.numberOfTracks, info); + Audio_setTitle("(%u/%u): %s", gPlayProperties.currentTrackNumber + 1, gPlayProperties.numberOfTracks, info); } else { Audio_setTitle("%s", info); } @@ -1214,36 +1214,35 @@ void audio_bitrate(const char *info) { Log_Printf(LOGLEVEL_INFO, "bitrate : %s", info); } -void audio_commercial(const char *info) { //duration in sec +void audio_commercial(const char *info) { // duration in sec Log_Printf(LOGLEVEL_INFO, "commercial : %s", info); } -void audio_icyurl(const char *info) { //homepage +void audio_icyurl(const char *info) { // homepage Log_Printf(LOGLEVEL_INFO, "icyurl : %s", info); } -void audio_lasthost(const char *info) { //stream URL played +void audio_lasthost(const char *info) { // stream URL played Log_Printf(LOGLEVEL_INFO, "lasthost : %s", info); } // id3 tag: save cover image -void audio_id3image(File& file, const size_t pos, const size_t size) { +void audio_id3image(File &file, const size_t pos, const size_t size) { // save cover image position and size for later use gPlayProperties.coverFilePos = pos; gPlayProperties.coverFileSize = size; // websocket and mqtt notify cover image has changed Web_SendWebsocketData(0, 40); - #ifdef MQTT_ENABLE - publishMqtt(topicCoverChangedState, "", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicCoverChangedState, "", false); +#endif } -void audio_eof_speech(const char *info){ +void audio_eof_speech(const char *info) { gPlayProperties.currentSpeechActive = false; } - // process audio sample extern (for bluetooth source) -void audio_process_i2s(uint32_t* sample, bool *continueI2S){ +void audio_process_i2s(uint32_t *sample, bool *continueI2S) { *continueI2S = !Bluetooth_Source_SendAudioData(sample); } diff --git a/src/AudioPlayer.h b/src/AudioPlayer.h index 64c835cc..7fcb8870 100644 --- a/src/AudioPlayer.h +++ b/src/AudioPlayer.h @@ -1,33 +1,33 @@ #pragma once typedef struct { // Bit field - uint8_t playMode: 4; // playMode - char **playlist; // playlist - char title[255]; // current title - bool repeatCurrentTrack: 1; // If current track should be looped - bool repeatPlaylist: 1; // If whole playlist should be looped - uint16_t currentTrackNumber: 9; // Current tracknumber - uint16_t numberOfTracks: 9; // Number of tracks in playlist - unsigned long startAtFilePos; // Offset to start play (in bytes) - double currentRelPos; // Current relative playPosition (in %) - bool sleepAfterCurrentTrack: 1; // If uC should go to sleep after current track - bool sleepAfterPlaylist: 1; // If uC should go to sleep after whole playlist - bool sleepAfter5Tracks: 1; // If uC should go to sleep after 5 tracks - bool saveLastPlayPosition: 1; // If playposition/current track should be saved (for AUDIOBOOK) - char playRfidTag[13]; // ID of RFID-tag that started playlist - bool pausePlay: 1; // If pause is active - bool trackFinished: 1; // If current track is finished - bool playlistFinished: 1; // If whole playlist is finished - uint8_t playUntilTrackNumber: 6; // Number of tracks to play after which uC goes to sleep - uint8_t seekmode: 2; // If seekmode is active and if yes: forward or backwards? - bool newPlayMono: 1; // true if mono; false if stereo (helper) - bool currentPlayMono: 1; // true if mono; false if stereo - bool isWebstream: 1; // Indicates if track currenty played is a webstream - uint8_t tellMode: 2; // Tell mode for text to speech announcments - bool currentSpeechActive: 1; // If speech-play is active - bool lastSpeechActive: 1; // If speech-play was active - size_t coverFilePos; // current cover file position - size_t coverFileSize; // current cover file size + uint8_t playMode : 4; // playMode + char **playlist; // playlist + char title[255]; // current title + bool repeatCurrentTrack : 1; // If current track should be looped + bool repeatPlaylist : 1; // If whole playlist should be looped + uint16_t currentTrackNumber : 9; // Current tracknumber + uint16_t numberOfTracks : 9; // Number of tracks in playlist + unsigned long startAtFilePos; // Offset to start play (in bytes) + double currentRelPos; // Current relative playPosition (in %) + bool sleepAfterCurrentTrack : 1; // If uC should go to sleep after current track + bool sleepAfterPlaylist : 1; // If uC should go to sleep after whole playlist + bool sleepAfter5Tracks : 1; // If uC should go to sleep after 5 tracks + bool saveLastPlayPosition : 1; // If playposition/current track should be saved (for AUDIOBOOK) + char playRfidTag[13]; // ID of RFID-tag that started playlist + bool pausePlay : 1; // If pause is active + bool trackFinished : 1; // If current track is finished + bool playlistFinished : 1; // If whole playlist is finished + uint8_t playUntilTrackNumber : 6; // Number of tracks to play after which uC goes to sleep + uint8_t seekmode : 2; // If seekmode is active and if yes: forward or backwards? + bool newPlayMono : 1; // true if mono; false if stereo (helper) + bool currentPlayMono : 1; // true if mono; false if stereo + bool isWebstream : 1; // Indicates if track currenty played is a webstream + uint8_t tellMode : 2; // Tell mode for text to speech announcments + bool currentSpeechActive : 1; // If speech-play is active + bool lastSpeechActive : 1; // If speech-play was active + size_t coverFilePos; // current cover file position + size_t coverFileSize; // current cover file size } playProps; extern playProps gPlayProperties; @@ -55,4 +55,4 @@ void AudioPlayer_SetupVolumeAndAmps(void); bool Audio_Detect_Mode_HP(bool _state); void Audio_setTitle(const char *format, ...); time_t AudioPlayer_GetPlayTimeSinceStart(void); -time_t AudioPlayer_GetPlayTimeAllTime(void); \ No newline at end of file +time_t AudioPlayer_GetPlayTimeAllTime(void); diff --git a/src/Battery.cpp b/src/Battery.cpp index 42371de7..0d9c7066 100644 --- a/src/Battery.cpp +++ b/src/Battery.cpp @@ -1,63 +1,66 @@ #include #include "settings.h" -#include "Log.h" + #include "Battery.h" -#include "Mqtt.h" + #include "Led.h" -#include "System.h" +#include "Log.h" +#include "Mqtt.h" #include "Power.h" #include "Rfid.h" +#include "System.h" #ifdef BATTERY_MEASURE_ENABLE - uint8_t batteryCheckInterval = s_batteryCheckInterval; - - void Battery_Init(void) { - uint32_t vInterval = gPrefsSettings.getUInt("vCheckIntv", 17777); - if (vInterval != 17777) { - batteryCheckInterval = vInterval; - Log_Printf(LOGLEVEL_INFO, batteryCheckIntervalFromNVS, vInterval); - } else { - gPrefsSettings.putUInt("vCheckIntv", batteryCheckInterval); - } +uint8_t batteryCheckInterval = s_batteryCheckInterval; - Battery_InitInner(); +void Battery_Init(void) { + uint32_t vInterval = gPrefsSettings.getUInt("vCheckIntv", 17777); + if (vInterval != 17777) { + batteryCheckInterval = vInterval; + Log_Printf(LOGLEVEL_INFO, batteryCheckIntervalFromNVS, vInterval); + } else { + gPrefsSettings.putUInt("vCheckIntv", batteryCheckInterval); + } - #ifdef SHUTDOWN_ON_BAT_CRITICAL - if (Battery_IsCritical()) { - Battery_LogStatus(); + Battery_InitInner(); - Log_Println(batteryCriticalMsg, LOGLEVEL_NOTICE); - // Power down and enter deepsleep - System_RequestSleep(); - } - #endif + #ifdef SHUTDOWN_ON_BAT_CRITICAL + if (Battery_IsCritical()) { + Battery_LogStatus(); + Log_Println(batteryCriticalMsg, LOGLEVEL_NOTICE); + // Power down and enter deepsleep + System_RequestSleep(); } + #endif +} + +// Measures battery as per interval or after bootup (after allowing a few seconds to settle down) +void Battery_Cyclic(void) { + static uint32_t lastBatteryCheckTimestamp = 0; + if ((millis() - lastBatteryCheckTimestamp >= batteryCheckInterval * 60000) || (!lastBatteryCheckTimestamp && millis() >= 10000)) { + Battery_CyclicInner(); + Battery_PublishMQTT(); + Battery_LogStatus(); - // Measures battery as per interval or after bootup (after allowing a few seconds to settle down) - void Battery_Cyclic(void) { - static uint32_t lastBatteryCheckTimestamp = 0; - if ((millis() - lastBatteryCheckTimestamp >= batteryCheckInterval * 60000) || (!lastBatteryCheckTimestamp && millis() >= 10000)) { - Battery_CyclicInner(); - Battery_PublishMQTT(); - Battery_LogStatus(); - - if (Battery_IsLow()) { - Log_Println(batteryLowMsg, LOGLEVEL_ERROR); - Led_Indicate(LedIndicatorType::VoltageWarning); - } - - #ifdef SHUTDOWN_ON_BAT_CRITICAL - if (Battery_IsCritical()) { - Log_Println(batteryCriticalMsg, LOGLEVEL_ERROR); - System_RequestSleep(); - } - #endif - - lastBatteryCheckTimestamp = millis(); + if (Battery_IsLow()) { + Log_Println(batteryLowMsg, LOGLEVEL_ERROR); + Led_Indicate(LedIndicatorType::VoltageWarning); } + + #ifdef SHUTDOWN_ON_BAT_CRITICAL + if (Battery_IsCritical()) { + Log_Println(batteryCriticalMsg, LOGLEVEL_ERROR); + System_RequestSleep(); + } + #endif + + lastBatteryCheckTimestamp = millis(); } +} #else // Battery Measure disabled, add dummy methods - void Battery_Cyclic(void) {} - void Battery_Init(void) {} +void Battery_Cyclic(void) { +} +void Battery_Init(void) { +} #endif diff --git a/src/Battery.h b/src/Battery.h index 9dac1c2e..78e13270 100644 --- a/src/Battery.h +++ b/src/Battery.h @@ -3,11 +3,11 @@ extern uint8_t batteryCheckInterval; #if defined(MEASURE_BATTERY_VOLTAGE) - extern float voltageIndicatorCritical; - extern float warningLowVoltage; - extern float warningCriticalVoltage; - extern float voltageIndicatorLow; - extern float voltageIndicatorHigh; +extern float voltageIndicatorCritical; +extern float warningLowVoltage; +extern float warningCriticalVoltage; +extern float voltageIndicatorLow; +extern float voltageIndicatorHigh; #endif void Battery_Init(void); @@ -21,7 +21,6 @@ bool Battery_IsCritical(void); void Battery_PublishMQTT(void); void Battery_LogStatus(void); - // Implementation specific tasks void Battery_CyclicInner(void); void Battery_InitInner(void); diff --git a/src/BatteryMax17055.cpp b/src/BatteryMax17055.cpp index c2ef62a3..4d2adc84 100644 --- a/src/BatteryMax17055.cpp +++ b/src/BatteryMax17055.cpp @@ -1,7 +1,8 @@ #include -#include "Battery.h" #include "settings.h" +#include "Battery.h" + #ifdef MEASURE_BATTERY_MAX17055 #include "Log.h" #include "Mqtt.h" @@ -10,144 +11,144 @@ #include #include - float batteryLow = s_batteryLow; - float batteryCritical = s_batteryCritical; - uint16_t cycles = 0; - - MAX17055 sensor; - - extern TwoWire i2cBusTwo; - - void Battery_InitInner() { - bool por = false; - sensor.init(s_batteryCapacity, s_emptyVoltage, s_recoveryVoltage, s_batteryChemistry, s_vCharge, s_resistSensor, por, &i2cBusTwo, &delay); - cycles = gPrefsSettings.getUShort("MAX17055_cycles", 0x0000); - Log_Printf(LOGLEVEL_DEBUG, "Cycles saved in NVS: %.2f", cycles / 100.0); - - // if power was lost, restore model params - if (por) { - // TODO i18n necessary? - Log_Println("Battery detected power loss - loading fuel gauge parameters.", LOGLEVEL_NOTICE); - uint16_t rComp0 = gPrefsSettings.getUShort("rComp0", 0xFFFF); - uint16_t tempCo = gPrefsSettings.getUShort("tempCo", 0xFFFF); - uint16_t fullCapRep = gPrefsSettings.getUShort("fullCapRep", 0xFFFF); - uint16_t fullCapNom = gPrefsSettings.getUShort("fullCapNom", 0xFFFF); - - Log_Println("Loaded MAX17055 battery model parameters from NVS:", LOGLEVEL_DEBUG); - Log_Printf(LOGLEVEL_DEBUG, "rComp0: 0x%.4x", rComp0); - Log_Printf(LOGLEVEL_DEBUG, "tempCo: 0x%.4x", tempCo); - Log_Printf(LOGLEVEL_DEBUG, "fullCapRep: 0x%.4x", fullCapRep); - Log_Printf(LOGLEVEL_DEBUG, "fullCapNom: 0x%.4x", fullCapNom); - - if ((rComp0 & tempCo & fullCapRep & fullCapNom) != 0xFFFF) { - Log_Println("Successfully loaded fuel gauge parameters.", LOGLEVEL_NOTICE); - sensor.restoreLearnedParameters(rComp0, tempCo, fullCapRep, cycles, fullCapNom); - } else { - Log_Println("Failed loading fuel gauge parameters.", LOGLEVEL_NOTICE); - } - } else { - Log_Println("Battery continuing normal operation", LOGLEVEL_DEBUG); - } - - Log_Println("MAX17055 init done. Battery configured with the following settings:", LOGLEVEL_DEBUG); - float val = sensor.getCapacity(); - Log_Printf(LOGLEVEL_DEBUG, "Design Capacity: %.2f mAh", val); - val = sensor.getEmptyVoltage() / 100.0; - Log_Printf(LOGLEVEL_DEBUG, "Empty Voltage: %.2f V", val); - uint16_t modelCfg = sensor.getModelCfg(); - Log_Printf(LOGLEVEL_DEBUG, "ModelCfg Value: 0x%.4x", modelCfg); - uint16_t cycles = sensor.getCycles(); - Log_Printf(LOGLEVEL_DEBUG, "Cycles: %.2f", cycles / 100.0); - - float vBatteryLow = gPrefsSettings.getFloat("batteryLow", 999.99); - if (vBatteryLow <= 999) { - batteryLow = vBatteryLow; - Log_Printf(LOGLEVEL_INFO, batteryLowFromNVS, batteryLow); +float batteryLow = s_batteryLow; +float batteryCritical = s_batteryCritical; +uint16_t cycles = 0; + +MAX17055 sensor; + +extern TwoWire i2cBusTwo; + +void Battery_InitInner() { + bool por = false; + sensor.init(s_batteryCapacity, s_emptyVoltage, s_recoveryVoltage, s_batteryChemistry, s_vCharge, s_resistSensor, por, &i2cBusTwo, &delay); + cycles = gPrefsSettings.getUShort("MAX17055_cycles", 0x0000); + Log_Printf(LOGLEVEL_DEBUG, "Cycles saved in NVS: %.2f", cycles / 100.0); + + // if power was lost, restore model params + if (por) { + // TODO i18n necessary? + Log_Println("Battery detected power loss - loading fuel gauge parameters.", LOGLEVEL_NOTICE); + uint16_t rComp0 = gPrefsSettings.getUShort("rComp0", 0xFFFF); + uint16_t tempCo = gPrefsSettings.getUShort("tempCo", 0xFFFF); + uint16_t fullCapRep = gPrefsSettings.getUShort("fullCapRep", 0xFFFF); + uint16_t fullCapNom = gPrefsSettings.getUShort("fullCapNom", 0xFFFF); + + Log_Println("Loaded MAX17055 battery model parameters from NVS:", LOGLEVEL_DEBUG); + Log_Printf(LOGLEVEL_DEBUG, "rComp0: 0x%.4x", rComp0); + Log_Printf(LOGLEVEL_DEBUG, "tempCo: 0x%.4x", tempCo); + Log_Printf(LOGLEVEL_DEBUG, "fullCapRep: 0x%.4x", fullCapRep); + Log_Printf(LOGLEVEL_DEBUG, "fullCapNom: 0x%.4x", fullCapNom); + + if ((rComp0 & tempCo & fullCapRep & fullCapNom) != 0xFFFF) { + Log_Println("Successfully loaded fuel gauge parameters.", LOGLEVEL_NOTICE); + sensor.restoreLearnedParameters(rComp0, tempCo, fullCapRep, cycles, fullCapNom); } else { - gPrefsSettings.putFloat("batteryLow", batteryLow); - } - - float vBatteryCritical = gPrefsSettings.getFloat("batteryCritical", 999.99); - if (vBatteryCritical <= 999) { - batteryCritical = vBatteryCritical; - Log_Printf(LOGLEVEL_INFO, batteryCriticalFromNVS, batteryCritical); - } else { - gPrefsSettings.putFloat("batteryCritical", batteryCritical); - } - } - - void Battery_CyclicInner() { - // It is recommended to save the learned capacity parameters every time bit 6 of the Cycles register toggles - uint16_t sensorCycles = sensor.getCycles(); - // sensorCycles = 0xFFFF likely means read error - if (sensor.getPresent() && sensorCycles != 0xFFFF && uint16_t(cycles + 0x0040) <= sensorCycles) { - Log_Println("Battery Cycle passed 64%, store MAX17055 learned parameters", LOGLEVEL_DEBUG); - uint16_t rComp0; - uint16_t tempCo; - uint16_t fullCapRep; - uint16_t fullCapNom; - sensor.getLearnedParameters(rComp0, tempCo, fullCapRep, sensorCycles, fullCapNom); - gPrefsSettings.putUShort("rComp0", rComp0); - gPrefsSettings.putUShort("tempCo", tempCo); - gPrefsSettings.putUShort("fullCapRep", fullCapRep); - gPrefsSettings.putUShort("MAX17055_cycles", sensorCycles); - gPrefsSettings.putUShort("fullCapNom", fullCapNom); - cycles = sensorCycles; + Log_Println("Failed loading fuel gauge parameters.", LOGLEVEL_NOTICE); } + } else { + Log_Println("Battery continuing normal operation", LOGLEVEL_DEBUG); } - float Battery_GetVoltage(void) { - return sensor.getInstantaneousVoltage(); + Log_Println("MAX17055 init done. Battery configured with the following settings:", LOGLEVEL_DEBUG); + float val = sensor.getCapacity(); + Log_Printf(LOGLEVEL_DEBUG, "Design Capacity: %.2f mAh", val); + val = sensor.getEmptyVoltage() / 100.0; + Log_Printf(LOGLEVEL_DEBUG, "Empty Voltage: %.2f V", val); + uint16_t modelCfg = sensor.getModelCfg(); + Log_Printf(LOGLEVEL_DEBUG, "ModelCfg Value: 0x%.4x", modelCfg); + uint16_t cycles = sensor.getCycles(); + Log_Printf(LOGLEVEL_DEBUG, "Cycles: %.2f", cycles / 100.0); + + float vBatteryLow = gPrefsSettings.getFloat("batteryLow", 999.99); + if (vBatteryLow <= 999) { + batteryLow = vBatteryLow; + Log_Printf(LOGLEVEL_INFO, batteryLowFromNVS, batteryLow); + } else { + gPrefsSettings.putFloat("batteryLow", batteryLow); } - void Battery_PublishMQTT() { - #ifdef MQTT_ENABLE - float voltage = Battery_GetVoltage(); - char vstr[6]; - snprintf(vstr, 6, "%.2f", voltage); - publishMqtt(topicBatteryVoltage, vstr, false); - - float soc = Battery_EstimateLevel() * 100; - snprintf(vstr, 6, "%.2f", soc); - publishMqtt(topicBatterySOC, vstr, false); - #endif + float vBatteryCritical = gPrefsSettings.getFloat("batteryCritical", 999.99); + if (vBatteryCritical <= 999) { + batteryCritical = vBatteryCritical; + Log_Printf(LOGLEVEL_INFO, batteryCriticalFromNVS, batteryCritical); + } else { + gPrefsSettings.putFloat("batteryCritical", batteryCritical); } - - void Battery_LogStatus(void) { - Log_Printf(LOGLEVEL_INFO, currentVoltageMsg, Battery_GetVoltage()); - Log_Printf(LOGLEVEL_INFO, currentChargeMsg, Battery_EstimateLevel() * 100); - Log_Printf(LOGLEVEL_INFO, batteryCurrentMsg, sensor.getAverageCurrent()); - Log_Printf(LOGLEVEL_INFO, batteryTempMsg, sensor.getTemperature()); - - // pretty useless because of low resolution - // Log_Printf(LOGLEVEL_INFO, "Max current to battery since last check: %.4f mA", sensor.getMaxCurrent()); - // Log_Printf(LOGLEVEL_INFO, "Min current to battery since last check: %.4f mA", sensor.getMinCurrent()); - // sensor.resetMaxMinCurrent(); - - Log_Printf(LOGLEVEL_INFO, batteryCyclesMsg, sensor.getCycles() / 100.0); +} + +void Battery_CyclicInner() { + // It is recommended to save the learned capacity parameters every time bit 6 of the Cycles register toggles + uint16_t sensorCycles = sensor.getCycles(); + // sensorCycles = 0xFFFF likely means read error + if (sensor.getPresent() && sensorCycles != 0xFFFF && uint16_t(cycles + 0x0040) <= sensorCycles) { + Log_Println("Battery Cycle passed 64%, store MAX17055 learned parameters", LOGLEVEL_DEBUG); + uint16_t rComp0; + uint16_t tempCo; + uint16_t fullCapRep; + uint16_t fullCapNom; + sensor.getLearnedParameters(rComp0, tempCo, fullCapRep, sensorCycles, fullCapNom); + gPrefsSettings.putUShort("rComp0", rComp0); + gPrefsSettings.putUShort("tempCo", tempCo); + gPrefsSettings.putUShort("fullCapRep", fullCapRep); + gPrefsSettings.putUShort("MAX17055_cycles", sensorCycles); + gPrefsSettings.putUShort("fullCapNom", fullCapNom); + cycles = sensorCycles; } - - float Battery_EstimateLevel(void) { - return sensor.getSOC() / 100; +} + +float Battery_GetVoltage(void) { + return sensor.getInstantaneousVoltage(); +} + +void Battery_PublishMQTT() { + #ifdef MQTT_ENABLE + float voltage = Battery_GetVoltage(); + char vstr[6]; + snprintf(vstr, 6, "%.2f", voltage); + publishMqtt(topicBatteryVoltage, vstr, false); + + float soc = Battery_EstimateLevel() * 100; + snprintf(vstr, 6, "%.2f", soc); + publishMqtt(topicBatterySOC, vstr, false); + #endif +} + +void Battery_LogStatus(void) { + Log_Printf(LOGLEVEL_INFO, currentVoltageMsg, Battery_GetVoltage()); + Log_Printf(LOGLEVEL_INFO, currentChargeMsg, Battery_EstimateLevel() * 100); + Log_Printf(LOGLEVEL_INFO, batteryCurrentMsg, sensor.getAverageCurrent()); + Log_Printf(LOGLEVEL_INFO, batteryTempMsg, sensor.getTemperature()); + + // pretty useless because of low resolution + // Log_Printf(LOGLEVEL_INFO, "Max current to battery since last check: %.4f mA", sensor.getMaxCurrent()); + // Log_Printf(LOGLEVEL_INFO, "Min current to battery since last check: %.4f mA", sensor.getMinCurrent()); + // sensor.resetMaxMinCurrent(); + + Log_Printf(LOGLEVEL_INFO, batteryCyclesMsg, sensor.getCycles() / 100.0); +} + +float Battery_EstimateLevel(void) { + return sensor.getSOC() / 100; +} + +bool Battery_IsLow(void) { + float soc = sensor.getSOC(); + if (soc > 100.0) { + Log_Println("Battery percentage reading invalid, try again.", LOGLEVEL_DEBUG); + soc = sensor.getSOC(); } - bool Battery_IsLow(void) { - float soc = sensor.getSOC(); - if (soc > 100.0) { - Log_Println("Battery percentage reading invalid, try again.", LOGLEVEL_DEBUG); - soc = sensor.getSOC(); - } + return soc < batteryLow; +} - return soc < batteryLow; +bool Battery_IsCritical(void) { + float soc = sensor.getSOC(); + if (soc > 100.0) { + Log_Println("Battery percentage reading invalid, try again.", LOGLEVEL_DEBUG); + soc = sensor.getSOC(); } - bool Battery_IsCritical(void) { - float soc = sensor.getSOC(); - if (soc > 100.0) { - Log_Println("Battery percentage reading invalid, try again.", LOGLEVEL_DEBUG); - soc = sensor.getSOC(); - } - - return soc < batteryCritical; - } + return soc < batteryCritical; +} #endif diff --git a/src/BatteryMeasureVoltage.cpp b/src/BatteryMeasureVoltage.cpp index 8f8b22c4..e14e867e 100644 --- a/src/BatteryMeasureVoltage.cpp +++ b/src/BatteryMeasureVoltage.cpp @@ -1,125 +1,137 @@ #include #include "settings.h" -#include "Log.h" + #include "Battery.h" -#include "Mqtt.h" #include "Led.h" +#include "Log.h" +#include "Mqtt.h" #include "System.h" // Only enable measurements if valid GPIO is used #if defined(MEASURE_BATTERY_VOLTAGE) && (VOLTAGE_READ_PIN >= 0 && VOLTAGE_READ_PIN <= 39) - constexpr uint16_t maxAnalogValue = 4095u; // Highest value given by analogRead(); don't change! - - float warningLowVoltage = s_warningLowVoltage; - float warningCriticalVoltage = s_warningCriticalVoltage; - float voltageIndicatorLow = s_voltageIndicatorLow; - float voltageIndicatorHigh = s_voltageIndicatorHigh; - - void Battery_InitInner() { - // Get voltages from NVS for Neopixel - float vLowIndicator = gPrefsSettings.getFloat("vIndicatorLow", 999.99); - if (vLowIndicator <= 999) { - voltageIndicatorLow = vLowIndicator; - Log_Printf(LOGLEVEL_INFO, voltageIndicatorLowFromNVS, vLowIndicator); - } else { // preseed if not set - gPrefsSettings.putFloat("vIndicatorLow", voltageIndicatorLow); - } - - float vHighIndicator = gPrefsSettings.getFloat("vIndicatorHigh", 999.99); - if (vHighIndicator <= 999) { - voltageIndicatorHigh = vHighIndicator; - Log_Printf(LOGLEVEL_INFO, voltageIndicatorHighFromNVS, vHighIndicator); - } else { - gPrefsSettings.putFloat("vIndicatorHigh", voltageIndicatorHigh); - } - - float vLowWarning = gPrefsSettings.getFloat("wLowVoltage", 999.99); - if (vLowWarning <= 999) { - warningLowVoltage = vLowWarning; - Log_Printf(LOGLEVEL_INFO, warningLowVoltageFromNVS, vLowWarning); - } else { - gPrefsSettings.putFloat("wLowVoltage", warningLowVoltage); - } - - float vCriticalWarning = gPrefsSettings.getFloat("wCritVoltage", 999.99); - if (vCriticalWarning <= 999) { - warningCriticalVoltage = vCriticalWarning; - Log_Printf(LOGLEVEL_INFO, warningCriticalVoltageFromNVS, vCriticalWarning); - } else { - gPrefsSettings.putFloat("wCritVoltage", warningCriticalVoltage); - } +constexpr uint16_t maxAnalogValue = 4095u; // Highest value given by analogRead(); don't change! + +float warningLowVoltage = s_warningLowVoltage; +float warningCriticalVoltage = s_warningCriticalVoltage; +float voltageIndicatorLow = s_voltageIndicatorLow; +float voltageIndicatorHigh = s_voltageIndicatorHigh; + +void Battery_InitInner() { + // Get voltages from NVS for Neopixel + float vLowIndicator = gPrefsSettings.getFloat("vIndicatorLow", 999.99); + if (vLowIndicator <= 999) { + voltageIndicatorLow = vLowIndicator; + Log_Printf(LOGLEVEL_INFO, voltageIndicatorLowFromNVS, vLowIndicator); + } else { // preseed if not set + gPrefsSettings.putFloat("vIndicatorLow", voltageIndicatorLow); } - - void Battery_CyclicInner() { - // no special cyclic task necessary for voltage measure + float vHighIndicator = gPrefsSettings.getFloat("vIndicatorHigh", 999.99); + if (vHighIndicator <= 999) { + voltageIndicatorHigh = vHighIndicator; + Log_Printf(LOGLEVEL_INFO, voltageIndicatorHighFromNVS, vHighIndicator); + } else { + gPrefsSettings.putFloat("vIndicatorHigh", voltageIndicatorHigh); } - // The average of several analog reads will be taken to reduce the noise (Note: One analog read takes ~10µs) - float Battery_GetVoltage(void) { - float factor = 1 / ((float) rdiv2 / (rdiv2 + rdiv1)); - float averagedAnalogValue = 0; - uint8_t i; - for (i = 0; i <= 19; i++) { - averagedAnalogValue += (float)analogRead(VOLTAGE_READ_PIN); - } - averagedAnalogValue /= 20.0; - return (averagedAnalogValue / maxAnalogValue) * referenceVoltage * factor + offsetVoltage; + float vLowWarning = gPrefsSettings.getFloat("wLowVoltage", 999.99); + if (vLowWarning <= 999) { + warningLowVoltage = vLowWarning; + Log_Printf(LOGLEVEL_INFO, warningLowVoltageFromNVS, vLowWarning); + } else { + gPrefsSettings.putFloat("wLowVoltage", warningLowVoltage); } - void Battery_PublishMQTT() { - #ifdef MQTT_ENABLE - float voltage = Battery_GetVoltage(); - char vstr[6]; - snprintf(vstr, 6, "%.2f", voltage); - publishMqtt(topicBatteryVoltage, vstr, false); - - float soc = Battery_EstimateLevel() * 100; - snprintf(vstr, 6, "%.2f", soc); - publishMqtt(topicBatterySOC, vstr, false); - #endif + float vCriticalWarning = gPrefsSettings.getFloat("wCritVoltage", 999.99); + if (vCriticalWarning <= 999) { + warningCriticalVoltage = vCriticalWarning; + Log_Printf(LOGLEVEL_INFO, warningCriticalVoltageFromNVS, vCriticalWarning); + } else { + gPrefsSettings.putFloat("wCritVoltage", warningCriticalVoltage); } - - void Battery_LogStatus(void) { - Log_Printf(LOGLEVEL_INFO, currentVoltageMsg, Battery_GetVoltage()); - Log_Printf(LOGLEVEL_INFO, currentChargeMsg, Battery_EstimateLevel() * 100); +} + +void Battery_CyclicInner() { + // no special cyclic task necessary for voltage measure +} + +// The average of several analog reads will be taken to reduce the noise (Note: One analog read takes ~10µs) +float Battery_GetVoltage(void) { + float factor = 1 / ((float) rdiv2 / (rdiv2 + rdiv1)); + float averagedAnalogValue = 0; + uint8_t i; + for (i = 0; i <= 19; i++) { + averagedAnalogValue += (float) analogRead(VOLTAGE_READ_PIN); } + averagedAnalogValue /= 20.0; + return (averagedAnalogValue / maxAnalogValue) * referenceVoltage * factor + offsetVoltage; +} - float Battery_EstimateLevel(void) { - float currentVoltage = Battery_GetVoltage(); - float vDiffIndicatorRange = voltageIndicatorHigh - voltageIndicatorLow; - float vDiffCurrent = currentVoltage - voltageIndicatorLow; - float estimatedLevel = vDiffCurrent / vDiffIndicatorRange; - if (estimatedLevel < 0) { // Don't return value < 0.0 - return 0.0F; - } - return (estimatedLevel > 1) ? 1.0F : estimatedLevel; // Don't return value > 1.0 +void Battery_PublishMQTT() { + #ifdef MQTT_ENABLE + float voltage = Battery_GetVoltage(); + char vstr[6]; + snprintf(vstr, 6, "%.2f", voltage); + publishMqtt(topicBatteryVoltage, vstr, false); + + float soc = Battery_EstimateLevel() * 100; + snprintf(vstr, 6, "%.2f", soc); + publishMqtt(topicBatterySOC, vstr, false); + #endif +} + +void Battery_LogStatus(void) { + Log_Printf(LOGLEVEL_INFO, currentVoltageMsg, Battery_GetVoltage()); + Log_Printf(LOGLEVEL_INFO, currentChargeMsg, Battery_EstimateLevel() * 100); +} + +float Battery_EstimateLevel(void) { + float currentVoltage = Battery_GetVoltage(); + float vDiffIndicatorRange = voltageIndicatorHigh - voltageIndicatorLow; + float vDiffCurrent = currentVoltage - voltageIndicatorLow; + float estimatedLevel = vDiffCurrent / vDiffIndicatorRange; + if (estimatedLevel < 0) { // Don't return value < 0.0 + return 0.0F; } + return (estimatedLevel > 1) ? 1.0F : estimatedLevel; // Don't return value > 1.0 +} - bool Battery_IsLow(void) { - return Battery_GetVoltage() < warningLowVoltage; - } +bool Battery_IsLow(void) { + return Battery_GetVoltage() < warningLowVoltage; +} - bool Battery_IsCritical(void) { - return Battery_GetVoltage() < warningCriticalVoltage; - } +bool Battery_IsCritical(void) { + return Battery_GetVoltage() < warningCriticalVoltage; +} #else #ifdef MEASURE_BATTERY_VOLTAGE - // add some dummy impls to make CI happy - - float warningLowVoltage = 0.4f; - float warningCriticalVoltage = 0.1f; - float voltageIndicatorLow = 3.0f; - float voltageIndicatorHigh = 4.2f; - - void Battery_InitInner(void) {} - void Battery_CyclicInner(void) {} - float Battery_GetVoltage(void) { return 4.2; } - void Battery_PublishMQTT(void) {} - void Battery_LogStatus(void) {} - float Battery_EstimateLevel(void) { return 42.0; } - bool Battery_IsLow(void) { return false; } - bool Battery_IsCritical(void) { return false; } +// add some dummy impls to make CI happy + +float warningLowVoltage = 0.4f; +float warningCriticalVoltage = 0.1f; +float voltageIndicatorLow = 3.0f; +float voltageIndicatorHigh = 4.2f; + +void Battery_InitInner(void) { +} +void Battery_CyclicInner(void) { +} +float Battery_GetVoltage(void) { + return 4.2; +} +void Battery_PublishMQTT(void) { +} +void Battery_LogStatus(void) { +} +float Battery_EstimateLevel(void) { + return 42.0; +} +bool Battery_IsLow(void) { + return false; +} +bool Battery_IsCritical(void) { + return false; +} #endif #endif diff --git a/src/Bluetooth.cpp b/src/Bluetooth.cpp index 2933234f..f45bdba2 100644 --- a/src/Bluetooth.cpp +++ b/src/Bluetooth.cpp @@ -1,12 +1,15 @@ #include -#include #include "settings.h" + #include "Bluetooth.h" + +#include "Common.h" #include "Log.h" #include "RotaryEncoder.h" -#include "Common.h" #include "System.h" +#include + #ifdef BLUETOOTH_ENABLE #include "esp_bt.h" #include "BluetoothA2DPSink.h" @@ -17,311 +20,313 @@ #define BLUETOOTHPLAYER_VOLUME_MAX 21u #define BLUETOOTHPLAYER_VOLUME_MIN 0u - BluetoothA2DPSink *a2dp_sink; - BluetoothA2DPSource *a2dp_source; - RingbufHandle_t audioSourceRingBuffer; - String btDeviceName; +BluetoothA2DPSink *a2dp_sink; +BluetoothA2DPSource *a2dp_source; +RingbufHandle_t audioSourceRingBuffer; +String btDeviceName; #endif #ifdef BLUETOOTH_ENABLE - const char *getType() { - if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { - return "sink"; - } else { - return "source"; - } +const char *getType() { + if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { + return "sink"; + } else { + return "source"; } +} #endif #ifdef BLUETOOTH_ENABLE - // for esp_a2d_connection_state_t see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/esp_a2dp.html#_CPPv426esp_a2d_connection_state_t - void connection_state_changed(esp_a2d_connection_state_t state, void *ptr) { - Log_Printf(LOGLEVEL_INFO, "Bluetooth %s => connection state: %s", getType(), ((BluetoothA2DPCommon *)ptr)->to_str(state)); - if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { - // for Neopixel (indicator LEDs) use the webstream mode - gPlayProperties.isWebstream = false; - gPlayProperties.pausePlay = false; - gPlayProperties.playlistFinished = true; - } +// for esp_a2d_connection_state_t see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/esp_a2dp.html#_CPPv426esp_a2d_connection_state_t +void connection_state_changed(esp_a2d_connection_state_t state, void *ptr) { + Log_Printf(LOGLEVEL_INFO, "Bluetooth %s => connection state: %s", getType(), ((BluetoothA2DPCommon *) ptr)->to_str(state)); + if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { + // for Neopixel (indicator LEDs) use the webstream mode + gPlayProperties.isWebstream = false; + gPlayProperties.pausePlay = false; + gPlayProperties.playlistFinished = true; } +} #endif - #ifdef BLUETOOTH_ENABLE - // for esp_a2d_audio_state_t see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/esp_a2dp.html#_CPPv421esp_a2d_audio_state_t - void audio_state_changed(esp_a2d_audio_state_t state, void *ptr) { - Log_Printf(LOGLEVEL_INFO, "Bluetooth %s => audio state: %s", getType(), ((BluetoothA2DPCommon *)ptr)->to_str(state)); - if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { - // set play/pause status - gPlayProperties.pausePlay = (state != ESP_A2D_AUDIO_STATE_STARTED); - // for Neopixel (indicator LEDs) use the webstream mode - gPlayProperties.playlistFinished = false; - gPlayProperties.isWebstream = true; - } +// for esp_a2d_audio_state_t see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/esp_a2dp.html#_CPPv421esp_a2d_audio_state_t +void audio_state_changed(esp_a2d_audio_state_t state, void *ptr) { + Log_Printf(LOGLEVEL_INFO, "Bluetooth %s => audio state: %s", getType(), ((BluetoothA2DPCommon *) ptr)->to_str(state)); + if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { + // set play/pause status + gPlayProperties.pausePlay = (state != ESP_A2D_AUDIO_STATE_STARTED); + // for Neopixel (indicator LEDs) use the webstream mode + gPlayProperties.playlistFinished = false; + gPlayProperties.isWebstream = true; } +} #endif #ifdef BLUETOOTH_ENABLE - // handle Bluetooth AVRC metadata - // https://docs.espressif.com/projects/esp-idf/en/release-v3.2/api-reference/bluetooth/esp_avrc.html - void avrc_metadata_callback(uint8_t id, const uint8_t *text) { - if (strlen((char *)text) == 0) { - return; - } - switch (id) { - case ESP_AVRC_MD_ATTR_TITLE: - // title - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Title: %s", text); - break; - case ESP_AVRC_MD_ATTR_ARTIST: - // artists - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Artist: %s", text); - break; - case ESP_AVRC_MD_ATTR_ALBUM: - // album - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Album: %s", text); - break; - case ESP_AVRC_MD_ATTR_TRACK_NUM: - // current track number - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Track-No: %s", text); - break; - case ESP_AVRC_MD_ATTR_NUM_TRACKS: - // number of tracks in playlist - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Number of tracks: %s", text); - break; - case ESP_AVRC_MD_ATTR_GENRE: - // genre - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Genre: %s", text); - break; - default: - // unknown/unsupported metadata - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC metadata rsp: attribute id 0x%x, %s", id, text); - break; - } +// handle Bluetooth AVRC metadata +// https://docs.espressif.com/projects/esp-idf/en/release-v3.2/api-reference/bluetooth/esp_avrc.html +void avrc_metadata_callback(uint8_t id, const uint8_t *text) { + if (strlen((char *) text) == 0) { + return; + } + switch (id) { + case ESP_AVRC_MD_ATTR_TITLE: + // title + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Title: %s", text); + break; + case ESP_AVRC_MD_ATTR_ARTIST: + // artists + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Artist: %s", text); + break; + case ESP_AVRC_MD_ATTR_ALBUM: + // album + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Album: %s", text); + break; + case ESP_AVRC_MD_ATTR_TRACK_NUM: + // current track number + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Track-No: %s", text); + break; + case ESP_AVRC_MD_ATTR_NUM_TRACKS: + // number of tracks in playlist + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Number of tracks: %s", text); + break; + case ESP_AVRC_MD_ATTR_GENRE: + // genre + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC Genre: %s", text); + break; + default: + // unknown/unsupported metadata + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => AVRC metadata rsp: attribute id 0x%x, %s", id, text); + break; } +} #endif #ifdef BLUETOOTH_ENABLE - // feed the A2DP source with audio data - int32_t get_data_channels(Frame *frame, int32_t channel_len) { - if (channel_len < 0 || frame == NULL) - return 0; - // Receive data from ring buffer - size_t len{}; - vRingbufferGetInfo(audioSourceRingBuffer, nullptr, nullptr, nullptr, nullptr, &len); - if (len < (channel_len * 4)) { - // Serial.println("Bluetooth source => not enough data"); - return 0; - }; - size_t sampleSize = 0; - uint8_t* sampleBuff; - sampleBuff = (uint8_t *)xRingbufferReceiveUpTo(audioSourceRingBuffer, &sampleSize, (TickType_t)portMAX_DELAY, channel_len * 4); - if (sampleBuff != NULL) { - // fill the channel data - for (int sample = 0; sample < (channel_len); ++sample) { - frame[sample].channel1 = (sampleBuff[sample * 4 + 3] << 8) | sampleBuff[sample * 4 + 2]; - frame[sample].channel2 = (sampleBuff[sample * 4 + 1] << 8) | sampleBuff[sample * 4]; - }; - vRingbufferReturnItem(audioSourceRingBuffer, (void *)sampleBuff); +// feed the A2DP source with audio data +int32_t get_data_channels(Frame *frame, int32_t channel_len) { + if (channel_len < 0 || frame == NULL) { + return 0; + } + // Receive data from ring buffer + size_t len {}; + vRingbufferGetInfo(audioSourceRingBuffer, nullptr, nullptr, nullptr, nullptr, &len); + if (len < (channel_len * 4)) { + // Serial.println("Bluetooth source => not enough data"); + return 0; + }; + size_t sampleSize = 0; + uint8_t *sampleBuff; + sampleBuff = (uint8_t *) xRingbufferReceiveUpTo(audioSourceRingBuffer, &sampleSize, (TickType_t) portMAX_DELAY, channel_len * 4); + if (sampleBuff != NULL) { + // fill the channel data + for (int sample = 0; sample < (channel_len); ++sample) { + frame[sample].channel1 = (sampleBuff[sample * 4 + 3] << 8) | sampleBuff[sample * 4 + 2]; + frame[sample].channel2 = (sampleBuff[sample * 4 + 1] << 8) | sampleBuff[sample * 4]; }; - return channel_len; + vRingbufferReturnItem(audioSourceRingBuffer, (void *) sampleBuff); }; + return channel_len; +}; #endif #ifdef BLUETOOTH_ENABLE - // callback which is notified on update Receiver RSSI - void rssi(esp_bt_gap_cb_param_t::read_rssi_delta_param &rssiParam) { - Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => RSSI value: %d", rssiParam.rssi_delta); - } +// callback which is notified on update Receiver RSSI +void rssi(esp_bt_gap_cb_param_t::read_rssi_delta_param &rssiParam) { + Log_Printf(LOGLEVEL_DEBUG, "Bluetooth => RSSI value: %d", rssiParam.rssi_delta); +} #endif #ifdef BLUETOOTH_ENABLE - // Callback notifying BT-source devices available. - // Return true to connect, false will continue scanning - bool scan_bluetooth_device_callback(const char* ssid, esp_bd_addr_t address, int rssi) { - Log_Printf(LOGLEVEL_INFO, "Bluetooth source => Device found: %s", ssid); +// Callback notifying BT-source devices available. +// Return true to connect, false will continue scanning +bool scan_bluetooth_device_callback(const char *ssid, esp_bd_addr_t address, int rssi) { + Log_Printf(LOGLEVEL_INFO, "Bluetooth source => Device found: %s", ssid); - if (btDeviceName == "") { - // no device name given, connect to first device found - return true; - } else { - // connect if device name (partially) matching, todo: compare case insensitive here? - return startsWith(ssid, btDeviceName.c_str()); - } + if (btDeviceName == "") { + // no device name given, connect to first device found + return true; + } else { + // connect if device name (partially) matching, todo: compare case insensitive here? + return startsWith(ssid, btDeviceName.c_str()); + } } #endif void Bluetooth_VolumeChanged(int _newVolume) { - #ifdef BLUETOOTH_ENABLE - if ((_newVolume < 0) || (_newVolume > 0x7F)) { - return; - } - // map bluetooth volume (0..127) to ESPuino volume (0..21) to - uint8_t _volume; - _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); - } - #endif +#ifdef BLUETOOTH_ENABLE + if ((_newVolume < 0) || (_newVolume > 0x7F)) { + return; + } + // map bluetooth volume (0..127) to ESPuino volume (0..21) to + uint8_t _volume; + _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); + } +#endif } void Bluetooth_Init(void) { - #ifdef BLUETOOTH_ENABLE - if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { - // bluetooth in sink mode (player acts as a BT-Speaker) - a2dp_sink = new BluetoothA2DPSink(); - i2s_pin_config_t pin_config = { - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - .mck_io_num = 0, - #endif - .bck_io_num = I2S_BCLK, - .ws_io_num = I2S_LRC, - .data_out_num = I2S_DOUT, - .data_in_num = I2S_PIN_NO_CHANGE}; - a2dp_sink->set_pin_config(pin_config); - a2dp_sink->activate_pin_code(false); - #ifdef PLAY_MONO_SPEAKER - a2dp_sink->set_mono_downmix(true); - #endif - a2dp_sink->set_auto_reconnect(true); - a2dp_sink->set_rssi_active(true); - a2dp_sink->set_rssi_callback(rssi); - // start bluetooth sink - a2dp_sink->start(nameBluetoothSinkDevice); - Log_Printf(LOGLEVEL_INFO, "Bluetooth sink started, Device: %s", nameBluetoothSinkDevice); - // connect events after startup - a2dp_sink->set_on_connection_state_changed(connection_state_changed, a2dp_sink); - a2dp_sink->set_on_audio_state_changed(audio_state_changed, a2dp_sink); - a2dp_sink->set_avrc_metadata_callback(avrc_metadata_callback); - a2dp_sink->set_on_volumechange(Bluetooth_VolumeChanged); - } else if (System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) { - // create audio source ringbuffer on demand - audioSourceRingBuffer = xRingbufferCreate(8192, RINGBUF_TYPE_BYTEBUF); - if (audioSourceRingBuffer == NULL) - Log_Println("cannot create audioSourceRingBuffer!", LOGLEVEL_ERROR); - // setup BT source - a2dp_source = new BluetoothA2DPSource(); +#ifdef BLUETOOTH_ENABLE + if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { + // bluetooth in sink mode (player acts as a BT-Speaker) + a2dp_sink = new BluetoothA2DPSink(); + i2s_pin_config_t pin_config = { + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + .mck_io_num = 0, + #endif + .bck_io_num = I2S_BCLK, + .ws_io_num = I2S_LRC, + .data_out_num = I2S_DOUT, + .data_in_num = I2S_PIN_NO_CHANGE + }; + a2dp_sink->set_pin_config(pin_config); + a2dp_sink->activate_pin_code(false); + #ifdef PLAY_MONO_SPEAKER + a2dp_sink->set_mono_downmix(true); + #endif + a2dp_sink->set_auto_reconnect(true); + a2dp_sink->set_rssi_active(true); + a2dp_sink->set_rssi_callback(rssi); + // start bluetooth sink + a2dp_sink->start(nameBluetoothSinkDevice); + Log_Printf(LOGLEVEL_INFO, "Bluetooth sink started, Device: %s", nameBluetoothSinkDevice); + // connect events after startup + a2dp_sink->set_on_connection_state_changed(connection_state_changed, a2dp_sink); + a2dp_sink->set_on_audio_state_changed(audio_state_changed, a2dp_sink); + a2dp_sink->set_avrc_metadata_callback(avrc_metadata_callback); + a2dp_sink->set_on_volumechange(Bluetooth_VolumeChanged); + } else if (System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) { + // create audio source ringbuffer on demand + audioSourceRingBuffer = xRingbufferCreate(8192, RINGBUF_TYPE_BYTEBUF); + if (audioSourceRingBuffer == NULL) { + Log_Println("cannot create audioSourceRingBuffer!", LOGLEVEL_ERROR); + } + // setup BT source + a2dp_source = new BluetoothA2DPSource(); - //a2dp_source->set_auto_reconnect(false); // auto reconnect - //a2dp_source->set_task_core(1); // task core - //a2dp_source->set_nvs_init(true); // erase/initialize NVS - //a2dp_source->set_ssp_enabled(true); // enable secure simple pairing + // a2dp_source->set_auto_reconnect(false); // auto reconnect + // a2dp_source->set_task_core(1); // task core + // a2dp_source->set_nvs_init(true); // erase/initialize NVS + // a2dp_source->set_ssp_enabled(true); // enable secure simple pairing - // pairing pin-code, see https://forum.espuino.de/t/neues-feature-bluetooth-kopfhoerer/1293/30 - String btPinCode = gPrefsSettings.getString("btPinCode", ""); - if (btPinCode != "") { - a2dp_source->set_ssp_enabled(true); - a2dp_source->set_pin_code(btPinCode.c_str()); - } - // start bluetooth source - a2dp_source->set_ssid_callback(scan_bluetooth_device_callback); - a2dp_source->start(get_data_channels); - // get device name - btDeviceName = ""; - if (gPrefsSettings.isKey("btDeviceName")) { - btDeviceName = gPrefsSettings.getString("btDeviceName", ""); - } - Log_Printf(LOGLEVEL_INFO, "Bluetooth source started, connect to device: '%s'", (btDeviceName == "") ? "connect to first device found" : btDeviceName.c_str()); - // connect events after startup - a2dp_source->set_on_connection_state_changed(connection_state_changed, a2dp_source); - a2dp_source->set_on_audio_state_changed(audio_state_changed, a2dp_source); - // max headphone volume (0..255): volume is controlled by audio class - a2dp_source->set_volume(127); - } else { - esp_bt_mem_release(ESP_BT_MODE_BTDM); + // pairing pin-code, see https://forum.espuino.de/t/neues-feature-bluetooth-kopfhoerer/1293/30 + String btPinCode = gPrefsSettings.getString("btPinCode", ""); + if (btPinCode != "") { + a2dp_source->set_ssp_enabled(true); + a2dp_source->set_pin_code(btPinCode.c_str()); } - #endif + // start bluetooth source + a2dp_source->set_ssid_callback(scan_bluetooth_device_callback); + a2dp_source->start(get_data_channels); + // get device name + btDeviceName = ""; + if (gPrefsSettings.isKey("btDeviceName")) { + btDeviceName = gPrefsSettings.getString("btDeviceName", ""); + } + Log_Printf(LOGLEVEL_INFO, "Bluetooth source started, connect to device: '%s'", (btDeviceName == "") ? "connect to first device found" : btDeviceName.c_str()); + // connect events after startup + a2dp_source->set_on_connection_state_changed(connection_state_changed, a2dp_source); + a2dp_source->set_on_audio_state_changed(audio_state_changed, a2dp_source); + // max headphone volume (0..255): volume is controlled by audio class + a2dp_source->set_volume(127); + } else { + esp_bt_mem_release(ESP_BT_MODE_BTDM); + } +#endif } void Bluetooth_Cyclic(void) { - #ifdef BLUETOOTH_ENABLE - if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { - esp_a2d_audio_state_t state = a2dp_sink->get_audio_state(); - // Reset Sleep Timer when audio is playing - if (state == ESP_A2D_AUDIO_STATE_STARTED) { - System_UpdateActivityTimer(); - } +#ifdef BLUETOOTH_ENABLE + if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { + esp_a2d_audio_state_t state = a2dp_sink->get_audio_state(); + // Reset Sleep Timer when audio is playing + if (state == ESP_A2D_AUDIO_STATE_STARTED) { + System_UpdateActivityTimer(); } - if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) && (a2dp_source)) { - esp_a2d_audio_state_t state = a2dp_source->get_audio_state(); - // Reset Sleep Timer when audio is playing - if (state == ESP_A2D_AUDIO_STATE_STARTED) { - System_UpdateActivityTimer(); - } + } + if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) && (a2dp_source)) { + esp_a2d_audio_state_t state = a2dp_source->get_audio_state(); + // Reset Sleep Timer when audio is playing + if (state == ESP_A2D_AUDIO_STATE_STARTED) { + System_UpdateActivityTimer(); } - #endif + } +#endif } void Bluetooth_PlayPauseTrack(void) { - #ifdef BLUETOOTH_ENABLE - if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { - esp_a2d_audio_state_t state = a2dp_sink->get_audio_state(); - if (state == ESP_A2D_AUDIO_STATE_STARTED) { - a2dp_sink->play(); - } else { - a2dp_sink->pause(); - } +#ifdef BLUETOOTH_ENABLE + if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { + esp_a2d_audio_state_t state = a2dp_sink->get_audio_state(); + if (state == ESP_A2D_AUDIO_STATE_STARTED) { + a2dp_sink->play(); + } else { + a2dp_sink->pause(); } - #endif + } +#endif } void Bluetooth_NextTrack(void) { - #ifdef BLUETOOTH_ENABLE - if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { - a2dp_sink->next(); - } - #endif +#ifdef BLUETOOTH_ENABLE + if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { + a2dp_sink->next(); + } +#endif } void Bluetooth_PreviousTrack(void) { - #ifdef BLUETOOTH_ENABLE - if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { - a2dp_sink->previous(); - } - #endif +#ifdef BLUETOOTH_ENABLE + if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink)) { + a2dp_sink->previous(); + } +#endif } // set volume from ESPuino to phone needs at least Arduino ESP version 2.0.0 void Bluetooth_SetVolume(const int32_t _newVolume, bool reAdjustRotary) { - #ifdef BLUETOOTH_ENABLE - if (!a2dp_sink) - return; - uint8_t _volume; - if (_newVolume < int32_t(BLUETOOTHPLAYER_VOLUME_MIN)) { - return; - } else if (_newVolume > BLUETOOTHPLAYER_VOLUME_MAX) { - return; - } else { - // map ESPuino min/max volume (0..21) to bluetooth volume (0..127) - _volume = map(_newVolume, BLUETOOTHPLAYER_VOLUME_MIN, BLUETOOTHPLAYER_VOLUME_MAX, 0, 0x7F); - a2dp_sink->set_volume(_volume); - if (reAdjustRotary) { - RotaryEncoder_Readjust(); - } +#ifdef BLUETOOTH_ENABLE + if (!a2dp_sink) { + return; + } + uint8_t _volume; + if (_newVolume < int32_t(BLUETOOTHPLAYER_VOLUME_MIN)) { + return; + } else if (_newVolume > BLUETOOTHPLAYER_VOLUME_MAX) { + return; + } else { + // map ESPuino min/max volume (0..21) to bluetooth volume (0..127) + _volume = map(_newVolume, BLUETOOTHPLAYER_VOLUME_MIN, BLUETOOTHPLAYER_VOLUME_MAX, 0, 0x7F); + a2dp_sink->set_volume(_volume); + if (reAdjustRotary) { + RotaryEncoder_Readjust(); } - #endif + } +#endif } -bool Bluetooth_Source_SendAudioData(uint32_t* sample) { - #ifdef BLUETOOTH_ENABLE - // send audio data to ringbuffer - if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) && (a2dp_source) && a2dp_source->is_connected()) { - return (pdTRUE == xRingbufferSend(audioSourceRingBuffer, sample, sizeof(uint32_t), (TickType_t)portMAX_DELAY)); - } else { - return false; - } - #else +bool Bluetooth_Source_SendAudioData(uint32_t *sample) { +#ifdef BLUETOOTH_ENABLE + // send audio data to ringbuffer + if ((System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) && (a2dp_source) && a2dp_source->is_connected()) { + return (pdTRUE == xRingbufferSend(audioSourceRingBuffer, sample, sizeof(uint32_t), (TickType_t) portMAX_DELAY)); + } else { return false; - #endif + } +#else + return false; +#endif } bool Bluetooth_Device_Connected() { - #ifdef BLUETOOTH_ENABLE - // send audio data to ringbuffer - return (((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink) && a2dp_sink->is_connected()) || - ((System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) && (a2dp_source) && a2dp_source->is_connected())); - #else - return false; - #endif +#ifdef BLUETOOTH_ENABLE + // send audio data to ringbuffer + return (((System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) && (a2dp_sink) && a2dp_sink->is_connected()) || ((System_GetOperationMode() == OPMODE_BLUETOOTH_SOURCE) && (a2dp_source) && a2dp_source->is_connected())); +#else + return false; +#endif } diff --git a/src/Bluetooth.h b/src/Bluetooth.h index f94f9592..c6d6d55b 100644 --- a/src/Bluetooth.h +++ b/src/Bluetooth.h @@ -1,6 +1,5 @@ #pragma once - void Bluetooth_Init(void); void Bluetooth_Cyclic(void); @@ -14,5 +13,5 @@ void Bluetooth_PreviousTrack(void); // Support for AVRC Commands starting from ESP32 Release 2.0.0 void Bluetooth_SetVolume(const int32_t _newVolume, bool reAdjustRotary); -bool Bluetooth_Source_SendAudioData(uint32_t* sample); +bool Bluetooth_Source_SendAudioData(uint32_t *sample); bool Bluetooth_Device_Connected(); diff --git a/src/Button.cpp b/src/Button.cpp index 1cdb96c8..7680a991 100644 --- a/src/Button.cpp +++ b/src/Button.cpp @@ -1,8 +1,10 @@ #include #include "settings.h" -#include "Log.h" + #include "Button.h" + #include "Cmd.h" +#include "Log.h" #include "Port.h" #include "System.h" @@ -42,12 +44,12 @@ bool gButtonInitComplete = false; #define EXPANDER_5_ENABLE #endif -t_button gButtons[7]; // next + prev + pplay + rotEnc + button4 + button5 + dummy-button +t_button gButtons[7]; // next + prev + pplay + rotEnc + button4 + button5 + dummy-button uint8_t gShutdownButton = 99; // Helper used for Neopixel: stores button-number of shutdown-button uint16_t gLongPressTime = 0; #ifdef PORT_EXPANDER_ENABLE - extern bool Port_AllowReadFromPortExpander; +extern bool Port_AllowReadFromPortExpander; #endif static volatile SemaphoreHandle_t Button_TimerSemaphore; @@ -57,82 +59,88 @@ static void IRAM_ATTR onTimer(); static void Button_DoButtonActions(void); void Button_Init() { - #if (WAKEUP_BUTTON >= 0 && WAKEUP_BUTTON <= MAX_GPIO) - if (ESP_ERR_INVALID_ARG == esp_sleep_enable_ext0_wakeup((gpio_num_t)WAKEUP_BUTTON, 0)) { - Log_Printf(LOGLEVEL_ERROR, wrongWakeUpGpio, WAKEUP_BUTTON); - } - #endif +#if (WAKEUP_BUTTON >= 0 && WAKEUP_BUTTON <= MAX_GPIO) + if (ESP_ERR_INVALID_ARG == esp_sleep_enable_ext0_wakeup((gpio_num_t) WAKEUP_BUTTON, 0)) { + Log_Printf(LOGLEVEL_ERROR, wrongWakeUpGpio, WAKEUP_BUTTON); + } +#endif - #ifdef NEOPIXEL_ENABLE // Try to find button that is used for shutdown via longpress-action (only necessary for Neopixel) - #if defined(BUTTON_0_ENABLE) || defined(EXPANDER_0_ENABLE) - #if (BUTTON_0_LONG == CMD_SLEEPMODE) - gShutdownButton = 0; - #endif +#ifdef NEOPIXEL_ENABLE // Try to find button that is used for shutdown via longpress-action (only necessary for Neopixel) + #if defined(BUTTON_0_ENABLE) || defined(EXPANDER_0_ENABLE) + #if (BUTTON_0_LONG == CMD_SLEEPMODE) + gShutdownButton = 0; #endif - #if defined(BUTTON_1_ENABLE) || defined(EXPANDER_1_ENABLE) - #if (BUTTON_1_LONG == CMD_SLEEPMODE) - gShutdownButton = 1; - #endif + #endif + #if defined(BUTTON_1_ENABLE) || defined(EXPANDER_1_ENABLE) + #if (BUTTON_1_LONG == CMD_SLEEPMODE) + gShutdownButton = 1; #endif - #if defined(BUTTON_2_ENABLE) || defined(EXPANDER_2_ENABLE) - #if (BUTTON_2_LONG == CMD_SLEEPMODE) - gShutdownButton = 2; - #endif + #endif + #if defined(BUTTON_2_ENABLE) || defined(EXPANDER_2_ENABLE) + #if (BUTTON_2_LONG == CMD_SLEEPMODE) + gShutdownButton = 2; #endif - #if defined(BUTTON_3_ENABLE) || defined(EXPANDER_3_ENABLE) - #if (BUTTON_3_LONG == CMD_SLEEPMODE) - gShutdownButton = 3; - #endif + #endif + #if defined(BUTTON_3_ENABLE) || defined(EXPANDER_3_ENABLE) + #if (BUTTON_3_LONG == CMD_SLEEPMODE) + gShutdownButton = 3; #endif - #if defined(BUTTON_4_ENABLE) || defined(EXPANDER_4_ENABLE) - #if (BUTTON_4_LONG == CMD_SLEEPMODE) - gShutdownButton = 4; - #endif + #endif + #if defined(BUTTON_4_ENABLE) || defined(EXPANDER_4_ENABLE) + #if (BUTTON_4_LONG == CMD_SLEEPMODE) + gShutdownButton = 4; #endif - #if defined(BUTTON_5_ENABLE) || defined(EXPANDER_5_ENABLE) - #if (BUTTON_5_LONG == CMD_SLEEPMODE) - gShutdownButton = 5; - #endif + #endif + #if defined(BUTTON_5_ENABLE) || defined(EXPANDER_5_ENABLE) + #if (BUTTON_5_LONG == CMD_SLEEPMODE) + gShutdownButton = 5; #endif #endif +#endif - // Activate internal pullups for all enabled buttons connected to GPIOs - #ifdef BUTTON_0_ENABLE - if (BUTTON_0_ACTIVE_STATE) - pinMode(NEXT_BUTTON, INPUT); - else - pinMode(NEXT_BUTTON, INPUT_PULLUP); - #endif - #ifdef BUTTON_1_ENABLE - if (BUTTON_1_ACTIVE_STATE) - pinMode(PREVIOUS_BUTTON, INPUT); - else - pinMode(PREVIOUS_BUTTON, INPUT_PULLUP); - #endif - #ifdef BUTTON_2_ENABLE - if (BUTTON_2_ACTIVE_STATE) - pinMode(PAUSEPLAY_BUTTON, INPUT); - else - pinMode(PAUSEPLAY_BUTTON, INPUT_PULLUP); - #endif - #ifdef BUTTON_3_ENABLE - if (BUTTON_3_ACTIVE_STATE) - pinMode(ROTARYENCODER_BUTTON, INPUT); - else - pinMode(ROTARYENCODER_BUTTON, INPUT_PULLUP); - #endif - #ifdef BUTTON_4_ENABLE - if (BUTTON_4_ACTIVE_STATE) - pinMode(BUTTON_4, INPUT); - else - pinMode(BUTTON_4, INPUT_PULLUP); - #endif - #ifdef BUTTON_5_ENABLE - if (BUTTON_5_ACTIVE_STATE) - pinMode(BUTTON_5, INPUT); - else - pinMode(BUTTON_5, INPUT_PULLUP); - #endif +// Activate internal pullups for all enabled buttons connected to GPIOs +#ifdef BUTTON_0_ENABLE + if (BUTTON_0_ACTIVE_STATE) { + pinMode(NEXT_BUTTON, INPUT); + } else { + pinMode(NEXT_BUTTON, INPUT_PULLUP); + } +#endif +#ifdef BUTTON_1_ENABLE + if (BUTTON_1_ACTIVE_STATE) { + pinMode(PREVIOUS_BUTTON, INPUT); + } else { + pinMode(PREVIOUS_BUTTON, INPUT_PULLUP); + } +#endif +#ifdef BUTTON_2_ENABLE + if (BUTTON_2_ACTIVE_STATE) { + pinMode(PAUSEPLAY_BUTTON, INPUT); + } else { + pinMode(PAUSEPLAY_BUTTON, INPUT_PULLUP); + } +#endif +#ifdef BUTTON_3_ENABLE + if (BUTTON_3_ACTIVE_STATE) { + pinMode(ROTARYENCODER_BUTTON, INPUT); + } else { + pinMode(ROTARYENCODER_BUTTON, INPUT_PULLUP); + } +#endif +#ifdef BUTTON_4_ENABLE + if (BUTTON_4_ACTIVE_STATE) { + pinMode(BUTTON_4, INPUT); + } else { + pinMode(BUTTON_4, INPUT_PULLUP); + } +#endif +#ifdef BUTTON_5_ENABLE + if (BUTTON_5_ACTIVE_STATE) { + pinMode(BUTTON_5, INPUT); + } else { + pinMode(BUTTON_5, INPUT_PULLUP); + } +#endif // Create 1000Hz-HW-Timer (currently only used for buttons) Button_TimerSemaphore = xSemaphoreCreateBinary(); @@ -146,34 +154,34 @@ void Button_Init() { void Button_Cyclic() { if (xSemaphoreTake(Button_TimerSemaphore, 0) == pdTRUE) { unsigned long currentTimestamp = millis(); - #ifdef PORT_EXPANDER_ENABLE - Port_Cyclic(); - #endif +#ifdef PORT_EXPANDER_ENABLE + Port_Cyclic(); +#endif if (System_AreControlsLocked()) { return; } - // Buttons can be mixed between GPIO and port-expander. - // But at the same time only one of them can be for example NEXT_BUTTON - #if defined(BUTTON_0_ENABLE) || defined(EXPANDER_0_ENABLE) - gButtons[0].currentState = Port_Read(NEXT_BUTTON) ^ BUTTON_0_ACTIVE_STATE; - #endif - #if defined(BUTTON_1_ENABLE) || defined(EXPANDER_1_ENABLE) - gButtons[1].currentState = Port_Read(PREVIOUS_BUTTON) ^ BUTTON_1_ACTIVE_STATE; - #endif - #if defined(BUTTON_2_ENABLE) || defined(EXPANDER_2_ENABLE) - gButtons[2].currentState = Port_Read(PAUSEPLAY_BUTTON) ^ BUTTON_2_ACTIVE_STATE; - #endif - #if defined(BUTTON_3_ENABLE) || defined(EXPANDER_3_ENABLE) - gButtons[3].currentState = Port_Read(ROTARYENCODER_BUTTON) ^ BUTTON_3_ACTIVE_STATE; - #endif - #if defined(BUTTON_4_ENABLE) || defined(EXPANDER_4_ENABLE) - gButtons[4].currentState = Port_Read(BUTTON_4) ^ BUTTON_4_ACTIVE_STATE; - #endif - #if defined(BUTTON_5_ENABLE) || defined(EXPANDER_5_ENABLE) - gButtons[5].currentState = Port_Read(BUTTON_5) ^ BUTTON_5_ACTIVE_STATE; - #endif +// Buttons can be mixed between GPIO and port-expander. +// But at the same time only one of them can be for example NEXT_BUTTON +#if defined(BUTTON_0_ENABLE) || defined(EXPANDER_0_ENABLE) + gButtons[0].currentState = Port_Read(NEXT_BUTTON) ^ BUTTON_0_ACTIVE_STATE; +#endif +#if defined(BUTTON_1_ENABLE) || defined(EXPANDER_1_ENABLE) + gButtons[1].currentState = Port_Read(PREVIOUS_BUTTON) ^ BUTTON_1_ACTIVE_STATE; +#endif +#if defined(BUTTON_2_ENABLE) || defined(EXPANDER_2_ENABLE) + gButtons[2].currentState = Port_Read(PAUSEPLAY_BUTTON) ^ BUTTON_2_ACTIVE_STATE; +#endif +#if defined(BUTTON_3_ENABLE) || defined(EXPANDER_3_ENABLE) + gButtons[3].currentState = Port_Read(ROTARYENCODER_BUTTON) ^ BUTTON_3_ACTIVE_STATE; +#endif +#if defined(BUTTON_4_ENABLE) || defined(EXPANDER_4_ENABLE) + gButtons[4].currentState = Port_Read(BUTTON_4) ^ BUTTON_4_ACTIVE_STATE; +#endif +#if defined(BUTTON_5_ENABLE) || defined(EXPANDER_5_ENABLE) + gButtons[5].currentState = Port_Read(BUTTON_5) ^ BUTTON_5_ACTIVE_STATE; +#endif // Iterate over all buttons in struct-array for (uint8_t i = 0; i < sizeof(gButtons) / sizeof(gButtons[0]); i++) { diff --git a/src/Button.h b/src/Button.h index 19cfa869..931f202d 100644 --- a/src/Button.h +++ b/src/Button.h @@ -1,10 +1,10 @@ #pragma once typedef struct { - bool lastState : 1; + bool lastState : 1; bool currentState : 1; - bool isPressed : 1; - bool isReleased : 1; + bool isPressed : 1; + bool isReleased : 1; unsigned long lastPressedTimestamp; unsigned long lastReleasedTimestamp; unsigned long firstPressedTimestamp; diff --git a/src/Cmd.cpp b/src/Cmd.cpp index 0d213aac..85b48485 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -1,6 +1,8 @@ #include #include "settings.h" + #include "Cmd.h" + #include "AudioPlayer.h" #include "Battery.h" #include "Bluetooth.h" @@ -17,14 +19,14 @@ void Cmd_Action(const uint16_t mod) { System_ToggleLockControls(); if (System_AreControlsLocked()) { Log_Println(modificatorAllButtonsLocked, LOGLEVEL_NOTICE); - #ifdef MQTT_ENABLE - publishMqtt(topicLockControlsState, "ON", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLockControlsState, "ON", false); +#endif } else { Log_Println(modificatorAllButtonsUnlocked, LOGLEVEL_NOTICE); - #ifdef MQTT_ENABLE - publishMqtt(topicLockControlsState, "OFF", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLockControlsState, "OFF", false); +#endif } System_IndicateOk(); break; @@ -34,7 +36,7 @@ void Cmd_Action(const uint16_t mod) { System_SetSleepTimer(15u); gPlayProperties.sleepAfterCurrentTrack = false; // deactivate/overwrite if already active - gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active + gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active gPlayProperties.playUntilTrackNumber = 0; System_IndicateOk(); break; @@ -44,7 +46,7 @@ void Cmd_Action(const uint16_t mod) { System_SetSleepTimer(30u); gPlayProperties.sleepAfterCurrentTrack = false; // deactivate/overwrite if already active - gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active + gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active gPlayProperties.playUntilTrackNumber = 0; System_IndicateOk(); break; @@ -54,7 +56,7 @@ void Cmd_Action(const uint16_t mod) { System_SetSleepTimer(60u); gPlayProperties.sleepAfterCurrentTrack = false; // deactivate/overwrite if already active - gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active + gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active gPlayProperties.playUntilTrackNumber = 0; System_IndicateOk(); break; @@ -64,7 +66,7 @@ void Cmd_Action(const uint16_t mod) { System_SetSleepTimer(120u); gPlayProperties.sleepAfterCurrentTrack = false; // deactivate/overwrite if already active - gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active + gPlayProperties.sleepAfterPlaylist = false; // deactivate/overwrite if already active gPlayProperties.playUntilTrackNumber = 0; System_IndicateOk(); break; @@ -83,23 +85,23 @@ void Cmd_Action(const uint16_t mod) { if (gPlayProperties.sleepAfterCurrentTrack) { gPlayProperties.sleepAfterCurrentTrack = false; Log_Println(modificatorSleepAtEOTd, LOGLEVEL_NOTICE); - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "0", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "0", false); +#endif Led_ResetToInitialBrightness(); } else { System_DisableSleepTimer(); gPlayProperties.sleepAfterCurrentTrack = true; Log_Println(modificatorSleepAtEOT, LOGLEVEL_NOTICE); - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "EOT", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "EOT", false); +#endif Led_ResetToNightBrightness(); } - #ifdef MQTT_ENABLE - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); +#endif System_IndicateOk(); break; } @@ -113,25 +115,25 @@ void Cmd_Action(const uint16_t mod) { if (gPlayProperties.sleepAfterPlaylist) { System_DisableSleepTimer(); gPlayProperties.sleepAfterPlaylist = false; - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "0", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "0", false); +#endif Led_ResetToInitialBrightness(); Log_Println(modificatorSleepAtEOPd, LOGLEVEL_NOTICE); } else { gPlayProperties.sleepAfterPlaylist = true; Led_ResetToNightBrightness(); Log_Println(modificatorSleepAtEOP, LOGLEVEL_NOTICE); - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "EOP", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "EOP", false); +#endif } gPlayProperties.sleepAfterCurrentTrack = false; gPlayProperties.playUntilTrackNumber = 0; - #ifdef MQTT_ENABLE - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); +#endif System_IndicateOk(); break; } @@ -150,31 +152,31 @@ void Cmd_Action(const uint16_t mod) { if (gPlayProperties.sleepAfter5Tracks) { gPlayProperties.sleepAfter5Tracks = false; gPlayProperties.playUntilTrackNumber = 0; - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "0", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "0", false); +#endif Led_ResetToInitialBrightness(); Log_Println(modificatorSleepd, LOGLEVEL_NOTICE); } else { gPlayProperties.sleepAfter5Tracks = true; if (gPlayProperties.currentTrackNumber + 5 > gPlayProperties.numberOfTracks) { // If currentTrack + 5 exceeds number of tracks in playlist, sleep after end of playlist gPlayProperties.sleepAfterPlaylist = true; - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "EOP", false); - #endif - } else { +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "EOP", false); +#endif + } else { gPlayProperties.playUntilTrackNumber = gPlayProperties.currentTrackNumber + 5; - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, "EO5T", false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, "EO5T", false); +#endif } Led_ResetToNightBrightness(); Log_Println(sleepTimerEO5, LOGLEVEL_NOTICE); } - #ifdef MQTT_ENABLE - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); +#endif System_IndicateOk(); break; } @@ -190,9 +192,9 @@ void Cmd_Action(const uint16_t mod) { Log_Println(modificatorPlaylistLoopActive, LOGLEVEL_NOTICE); } gPlayProperties.repeatPlaylist = !gPlayProperties.repeatPlaylist; - #ifdef MQTT_ENABLE - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); +#endif System_IndicateOk(); } break; @@ -209,18 +211,18 @@ void Cmd_Action(const uint16_t mod) { Log_Println(modificatorTrackActive, LOGLEVEL_NOTICE); } gPlayProperties.repeatCurrentTrack = !gPlayProperties.repeatCurrentTrack; - #ifdef MQTT_ENABLE - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); +#endif System_IndicateOk(); } break; } case CMD_DIMM_LEDS_NIGHTMODE: { - #ifdef MQTT_ENABLE - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); +#endif Log_Println(ledsDimmedToNightmode, LOGLEVEL_INFO); Led_ResetToNightBrightness(); System_IndicateOk(); @@ -234,44 +236,44 @@ void Cmd_Action(const uint16_t mod) { break; } - #ifdef BLUETOOTH_ENABLE - case CMD_TOGGLE_BLUETOOTH_SINK_MODE: { - if (System_GetOperationModeFromNvs() == OPMODE_NORMAL) { - System_IndicateOk(); - System_SetOperationMode(OPMODE_BLUETOOTH_SINK); - } else if (System_GetOperationModeFromNvs() == OPMODE_BLUETOOTH_SINK) { - System_IndicateOk(); - System_SetOperationMode(OPMODE_NORMAL); - } else { - System_IndicateError(); - } - break; +#ifdef BLUETOOTH_ENABLE + case CMD_TOGGLE_BLUETOOTH_SINK_MODE: { + if (System_GetOperationModeFromNvs() == OPMODE_NORMAL) { + System_IndicateOk(); + System_SetOperationMode(OPMODE_BLUETOOTH_SINK); + } else if (System_GetOperationModeFromNvs() == OPMODE_BLUETOOTH_SINK) { + System_IndicateOk(); + System_SetOperationMode(OPMODE_NORMAL); + } else { + System_IndicateError(); } - case CMD_TOGGLE_BLUETOOTH_SOURCE_MODE: { - if (System_GetOperationModeFromNvs() == OPMODE_NORMAL) { - System_IndicateOk(); - System_SetOperationMode(OPMODE_BLUETOOTH_SOURCE); - } else if (System_GetOperationModeFromNvs() == OPMODE_BLUETOOTH_SOURCE) { - System_IndicateOk(); - System_SetOperationMode(OPMODE_NORMAL); - } else { - System_IndicateError(); - } - break; + break; + } + case CMD_TOGGLE_BLUETOOTH_SOURCE_MODE: { + if (System_GetOperationModeFromNvs() == OPMODE_NORMAL) { + System_IndicateOk(); + System_SetOperationMode(OPMODE_BLUETOOTH_SOURCE); + } else if (System_GetOperationModeFromNvs() == OPMODE_BLUETOOTH_SOURCE) { + System_IndicateOk(); + System_SetOperationMode(OPMODE_NORMAL); + } else { + System_IndicateError(); } - #endif + break; + } +#endif - #ifdef FTP_ENABLE - case CMD_ENABLE_FTP_SERVER: { - if (millis() <= 30000) { // Only allow to enable FTP within the first 30s after start (to prevent children it mess it up) - Ftp_EnableServer(); - } else { - Log_Println(ftpEnableTooLate, LOGLEVEL_ERROR); - System_IndicateError(); - } - break; +#ifdef FTP_ENABLE + case CMD_ENABLE_FTP_SERVER: { + if (millis() <= 30000) { // Only allow to enable FTP within the first 30s after start (to prevent children it mess it up) + Ftp_EnableServer(); + } else { + Log_Println(ftpEnableTooLate, LOGLEVEL_ERROR); + System_IndicateError(); } - #endif + break; + } +#endif case CMD_TELL_IP_ADDRESS: { if (Wlan_IsConnected()) { @@ -285,7 +287,7 @@ void Cmd_Action(const uint16_t mod) { } break; } - + case CMD_TELL_CURRENT_TIME: { if (Wlan_IsConnected()) { gPlayProperties.tellMode = TTS_CURRENT_TIME; @@ -356,15 +358,15 @@ void Cmd_Action(const uint16_t mod) { } else { Bluetooth_SetVolume(AudioPlayer_GetCurrentVolume() - 1, true); } - break; + break; } case CMD_MEASUREBATTERY: { - #ifdef BATTERY_MEASURE_ENABLE - Battery_LogStatus(); - Battery_PublishMQTT(); - Led_Indicate(LedIndicatorType::Voltage); - #endif +#ifdef BATTERY_MEASURE_ENABLE + Battery_LogStatus(); + Battery_PublishMQTT(); + Led_Indicate(LedIndicatorType::Voltage); +#endif break; } @@ -393,12 +395,12 @@ void Cmd_Action(const uint16_t mod) { break; } - #ifdef ENABLE_ESPUINO_DEBUG - case PRINT_TASK_STATS: { - System_esp_print_tasks(); - break; - } - #endif +#ifdef ENABLE_ESPUINO_DEBUG + case PRINT_TASK_STATS: { + System_esp_print_tasks(); + break; + } +#endif default: { Log_Printf(LOGLEVEL_ERROR, modificatorDoesNotExist, mod); diff --git a/src/Common.h b/src/Common.h index d00213bf..15881097 100644 --- a/src/Common.h +++ b/src/Common.h @@ -3,11 +3,10 @@ // FilePathLength #define MAX_FILEPATH_LENTGH 256 -constexpr char stringDelimiter[] = "#"; // Character used to encapsulate data in linear NVS-strings (don't change) +constexpr char stringDelimiter[] = "#"; // Character used to encapsulate data in linear NVS-strings (don't change) constexpr char stringOuterDelimiter[] = "^"; // Character used to encapsulate encapsulated data along with RFID-ID in backup-file -inline bool isNumber(const char *str) -{ +inline bool isNumber(const char *str) { int i = 0; while (*(str + i) != '\0') { @@ -18,7 +17,7 @@ inline bool isNumber(const char *str) if (i > 0) { return true; - } else{ + } else { return false; } } @@ -50,7 +49,7 @@ inline bool endsWith(const char *str, const char *suf) { inline void convertFilenameToAscii(String utf8String, char *asciiString) { // Arduino >= 2.0.5 filenames are already unicode, copy to result here without UTF-8 decoding - strncpy(asciiString, (char *) utf8String.c_str(), utf8String.length() / sizeof(asciiString[0])); + strncpy(asciiString, (char *) utf8String.c_str(), utf8String.length() / sizeof(asciiString[0])); asciiString[utf8String.length()] = 0; } diff --git a/src/Ftp.cpp b/src/Ftp.cpp index f8d1ff76..e7c88c97 100644 --- a/src/Ftp.cpp +++ b/src/Ftp.cpp @@ -1,20 +1,23 @@ #include -#include #include "settings.h" + #include "Ftp.h" + #include "Log.h" #include "MemX.h" #include "SdCard.h" #include "System.h" #include "Wlan.h" +#include + #ifdef FTP_ENABLE #include "ESP-FTP-Server-Lib.h" #endif // FTP -String Ftp_User = "esp32"; // FTP-user (default; can be changed later via GUI) -String Ftp_Password = "esp32"; // FTP-password (default; can be changed later via GUI) +String Ftp_User = "esp32"; // FTP-user (default; can be changed later via GUI) +String Ftp_Password = "esp32"; // FTP-password (default; can be changed later via GUI) // FTP #ifdef FTP_ENABLE @@ -30,7 +33,7 @@ void Ftp_Init(void) { // Get FTP-user from NVS String nvsFtpUser = gPrefsSettings.getString("ftpuser", "-1"); if (!nvsFtpUser.compareTo("-1")) { - gPrefsSettings.putString("ftpuser", (String)Ftp_User); + gPrefsSettings.putString("ftpuser", (String) Ftp_User); Log_Println(wroteFtpUserToNvs, LOGLEVEL_ERROR); } else { Ftp_User = nvsFtpUser; @@ -40,7 +43,7 @@ void Ftp_Init(void) { // Get FTP-password from NVS String nvsFtpPassword = gPrefsSettings.getString("ftppassword", "-1"); if (!nvsFtpPassword.compareTo("-1")) { - gPrefsSettings.putString("ftppassword", (String)Ftp_Password); + gPrefsSettings.putString("ftppassword", (String) Ftp_Password); Log_Println(wroteFtpPwdToNvs, LOGLEVEL_ERROR); } else { Ftp_Password = nvsFtpPassword; @@ -49,32 +52,32 @@ void Ftp_Init(void) { } void Ftp_Cyclic(void) { - #ifdef FTP_ENABLE - ftpManager(); +#ifdef FTP_ENABLE + ftpManager(); - if (WL_CONNECTED == WiFi.status()) { - if (ftpEnableLastStatus && ftpEnableCurrentStatus) { - ftpSrv->handle(); - } + if (WL_CONNECTED == WiFi.status()) { + if (ftpEnableLastStatus && ftpEnableCurrentStatus) { + ftpSrv->handle(); } + } - if (ftpEnableLastStatus && ftpEnableCurrentStatus) { - if (ftpSrv->countConnections() > 0) { - System_UpdateActivityTimer(); // Re-adjust timer while client is connected to avoid ESP falling asleep - } + if (ftpEnableLastStatus && ftpEnableCurrentStatus) { + if (ftpSrv->countConnections() > 0) { + System_UpdateActivityTimer(); // Re-adjust timer while client is connected to avoid ESP falling asleep } - #endif + } +#endif } void Ftp_EnableServer(void) { - #ifdef FTP_ENABLE - if (Wlan_IsConnected() && !ftpEnableLastStatus && !ftpEnableCurrentStatus) { - ftpEnableLastStatus = true; - #else - if (Wlan_IsConnected()) { - #endif +#ifdef FTP_ENABLE + if (Wlan_IsConnected() && !ftpEnableLastStatus && !ftpEnableCurrentStatus) { + ftpEnableLastStatus = true; +#else + if (Wlan_IsConnected()) { +#endif - System_IndicateOk(); + System_IndicateOk(); } else { Log_Println(unableToStartFtpServer, LOGLEVEL_ERROR); System_IndicateError(); @@ -83,16 +86,16 @@ void Ftp_EnableServer(void) { // Creates FTP-instance only when requested void ftpManager(void) { - #ifdef FTP_ENABLE - if (ftpEnableLastStatus && !ftpEnableCurrentStatus) { - Log_Printf(LOGLEVEL_DEBUG, freeHeapWithoutFtp, ESP.getFreeHeap()); - ftpEnableCurrentStatus = true; - ftpSrv = new FTPServer(); - ftpSrv->addUser(Ftp_User, Ftp_Password); - ftpSrv->addFilesystem("SD-Card", &gFSystem); - ftpSrv->begin(); - Log_Printf(LOGLEVEL_DEBUG, freeHeapWithFtp, ESP.getFreeHeap()); - Log_Println(ftpServerStarted, LOGLEVEL_NOTICE); - } - #endif +#ifdef FTP_ENABLE + if (ftpEnableLastStatus && !ftpEnableCurrentStatus) { + Log_Printf(LOGLEVEL_DEBUG, freeHeapWithoutFtp, ESP.getFreeHeap()); + ftpEnableCurrentStatus = true; + ftpSrv = new FTPServer(); + ftpSrv->addUser(Ftp_User, Ftp_Password); + ftpSrv->addFilesystem("SD-Card", &gFSystem); + ftpSrv->begin(); + Log_Printf(LOGLEVEL_DEBUG, freeHeapWithFtp, ESP.getFreeHeap()); + Log_Println(ftpServerStarted, LOGLEVEL_NOTICE); + } +#endif } diff --git a/src/Ftp.h b/src/Ftp.h index fc43124a..dd13cb90 100644 --- a/src/Ftp.h +++ b/src/Ftp.h @@ -1,7 +1,7 @@ #pragma once -constexpr uint8_t ftpUserLength = 10u; // Length will be published n-1 as maxlength to GUI -constexpr uint8_t ftpPasswordLength = 15u; // Length will be published n-1 as maxlength to GUI +constexpr uint8_t ftpUserLength = 10u; // Length will be published n-1 as maxlength to GUI +constexpr uint8_t ftpPasswordLength = 15u; // Length will be published n-1 as maxlength to GUI void Ftp_Init(void); void Ftp_Cyclic(void); diff --git a/src/HallEffectSensor.cpp b/src/HallEffectSensor.cpp index cb9f95c1..6244b51a 100644 --- a/src/HallEffectSensor.cpp +++ b/src/HallEffectSensor.cpp @@ -1,10 +1,11 @@ // NIKO-AT 04.12.2022 Project ESPuino new feature: https://forum.espuino.de/t/magnetische-hockey-tags/1449/35 #include -#include "HallEffectSensor.h" -#include "System.h" #include "settings.h" -#include "Log.h" +#include "HallEffectSensor.h" + +#include "Log.h" +#include "System.h" #ifdef HALLEFFECT_SENSOR_ENABLE @@ -14,144 +15,146 @@ // gPrefs VarNames #define NULLFIELDVALUENAME "HES_NullValue" - - HallEffectSensor gHallEffectSensor; - - - HallEffectSensor::HallEffectSensor() { - pinMode(HallEffectSensor_PIN, INPUT); - }; - - // private - void HallEffectSensor::LoadNullFieldValueFromNVS() { - nullFieldValue = gPrefsSettings.getUShort(NULLFIELDVALUENAME, 0); - Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> NullFieldValue from NVS:%d", nullFieldValue); +HallEffectSensor gHallEffectSensor; + +HallEffectSensor::HallEffectSensor() { + pinMode(HallEffectSensor_PIN, INPUT); +}; + +// private +void HallEffectSensor::LoadNullFieldValueFromNVS() { + nullFieldValue = gPrefsSettings.getUShort(NULLFIELDVALUENAME, 0); + Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> NullFieldValue from NVS:%d", nullFieldValue); +} + +bool HallEffectSensor::SaveToNullFieldValueNVS(uint16_t val) { + uint16_t diff = abs(val - nullFieldValue); + bool res = (gPrefsSettings.putUShort(NULLFIELDVALUENAME, val) == 2); + const char *resMsg = "ERROR"; + if (res) { + resMsg = "OK"; + nullFieldValue = val; } - - bool HallEffectSensor::SaveToNullFieldValueNVS(uint16_t val) { - uint16_t diff = abs(val - nullFieldValue); - bool res = (gPrefsSettings.putUShort(NULLFIELDVALUENAME, val) == 2); - const char *resMsg = "ERROR"; - if (res) { - resMsg = "OK"; - nullFieldValue = val; + Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> Save NullFieldValue in NVS> Result:%s> NullValue:%d, diff:%d", resMsg, val, diff); + return res; +} + +void HallEffectSensor::StartDebugging() { + maxVal = 0; + minVal = 9999; + diffVal = 0; + lastCalibrationSubCallMS = 0; + calibrationFctCalls = 0; +}; + +// public +void HallEffectSensor::init() { + LoadNullFieldValueFromNVS(); + #ifdef HallEffectDebug + gHallEffectSensor.calibration(); + #else + int sva = gHallEffectSensor.readSensorValueAverage(true); + // check calibration + int diff = abs(sva - nullFieldValue); + if ((nullFieldValue < 1) || ((diff > 5) && (diff < HallEffectMaxDiffValueReCalibrate))) { + SaveToNullFieldValueNVS(sva); + } else if (diff >= HallEffectMinDiffValue) { + diff = sva - nullFieldValue; + byte nr = 1; + if (diff > 0) { + nr = 2; } - Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> Save NullFieldValue in NVS> Result:%s> NullValue:%d, diff:%d", resMsg, val, diff); - return res; + Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> No AutoCalibration> TAG side:%d detected", nr); + } else { + Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> No AutoCalibration> Difference too small> diff:%d", diff); } - - void HallEffectSensor::StartDebugging() { - maxVal = 0; - minVal = 9999; - diffVal = 0; - lastCalibrationSubCallMS = 0; - calibrationFctCalls = 0; - }; - - // public - void HallEffectSensor::init() { - LoadNullFieldValueFromNVS(); - #ifdef HallEffectDebug - gHallEffectSensor.calibration(); - #else - int sva = gHallEffectSensor.readSensorValueAverage(true); - // check calibration - int diff = abs(sva - nullFieldValue); - if ((nullFieldValue < 1) || ((diff > 5) && (diff < HallEffectMaxDiffValueReCalibrate))) { - SaveToNullFieldValueNVS(sva); - } else if (diff >= HallEffectMinDiffValue) { - diff = sva - nullFieldValue; - byte nr = 1; - if (diff > 0) - nr = 2; - Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> No AutoCalibration> TAG side:%d detected", nr); - } else { - Log_Printf(LOGLEVEL_INFO, "HallEffectSensor> No AutoCalibration> Difference too small> diff:%d", diff); - } - #endif + #endif +} + +void HallEffectSensor::cyclic() { + #ifdef HallEffectDebug + if ((calibrationFctCalls < maxCalibrationFctCalls) && (millis() > (lastCalibrationSubCallMS + calibrationFctCallsPauseMS))) { + readSensorValueAverage(false); + calibrationFctCalls++; + Log_Printf(LOGLEVEL_INFO, "%d. calibration-loop of HallEffectSensor (make sure NO TAG is/was near reader!) ...", calibrationFctCalls); + lastCalibrationSubCallMS = millis(); } - - void HallEffectSensor::cyclic() { + if (calibrationFctCalls == maxCalibrationFctCalls) { // Log results + uint16_t sva = (maxVal + minVal) / 2; + Log_Printf(LOGLEVEL_INFO, "Finished calibration of HallEffectSensor> HES_Uav:%d (min:%d, max:%d, (diff/2):%d, probes:%d)", sva, minVal, maxVal, diffVal / 2, calibrationProbes); + calibrationFctCalls++; // stop logging results #ifdef HallEffectDebug - if ((calibrationFctCalls < maxCalibrationFctCalls) && (millis() > (lastCalibrationSubCallMS + calibrationFctCallsPauseMS))) { - readSensorValueAverage(false); - calibrationFctCalls++; - Log_Printf(LOGLEVEL_INFO, "%d. calibration-loop of HallEffectSensor (make sure NO TAG is/was near reader!) ...", calibrationFctCalls); - lastCalibrationSubCallMS = millis(); - } - if (calibrationFctCalls == maxCalibrationFctCalls) { // Log results - uint16_t sva = (maxVal + minVal) / 2; - Log_Printf(LOGLEVEL_INFO, "Finished calibration of HallEffectSensor> HES_Uav:%d (min:%d, max:%d, (diff/2):%d, probes:%d)", sva, minVal, maxVal, diffVal / 2, calibrationProbes); - calibrationFctCalls++; // stop logging results - #ifdef HallEffectDebug - calibration(); - delay(100); - #endif - } + calibration(); + delay(100); #endif - }; - - uint16_t HallEffectSensor::readSensorValueAverage(bool doLog) { - // read analog value HallEffectAverageProbes times and return average - int sum = 0; - int cnt = 0; - for (int i = 0; i < HallEffectAverageProbesMS * 40; i++) { - uint16_t v = analogRead(HallEffectSensor_PIN); - sum += v; - cnt++; - delayMicroseconds(25); - } - uint16_t av = sum / cnt; - // update statistic - if (av > maxVal) - maxVal = av; - if (av < minVal) - minVal = av; - diffVal = maxVal - minVal; - calibrationProbes++; - if (doLog) { - Log_Printf(LOGLEVEL_INFO, "Read HallEffectSensor> value:%d", av); - } - return av; - }; - - bool HallEffectSensor::saveActualFieldValue2NVS() { - uint16_t sva = gHallEffectSensor.readSensorValueAverage(true); - bool res = SaveToNullFieldValueNVS(sva); - LoadNullFieldValueFromNVS(); - return res; - }; - - uint8_t HallEffectSensor::waitForState(uint16_t waitMS) { - // wait for magnetic north or south - lastWaitForState = 0; - unsigned long int startms = millis(); - ; - uint16_t sav; - do { - sav = readSensorValueAverage(true); - if (sav < nullFieldValue - HallEffectMinDiffValue) - lastWaitForState = 1; - else if (sav > nullFieldValue + HallEffectMinDiffValue) - lastWaitForState = 2; - else - delay(50); - } while ((lastWaitForState == 0) && (millis() < (startms + waitMS))); - lastWaitForStateMS = millis() - startms; - Log_Printf(LOGLEVEL_INFO, "HallEffectSensor waitForState> fieldValue:%d => state:%d, (duration:%d ms)", sav, lastWaitForState, lastWaitForStateMS); - return lastWaitForState; - }; - - uint16_t HallEffectSensor::NullFieldValue() { - return nullFieldValue; } - - int HallEffectSensor::LastWaitForStateMS() { - return lastWaitForStateMS; + #endif +}; + +uint16_t HallEffectSensor::readSensorValueAverage(bool doLog) { + // read analog value HallEffectAverageProbes times and return average + int sum = 0; + int cnt = 0; + for (int i = 0; i < HallEffectAverageProbesMS * 40; i++) { + uint16_t v = analogRead(HallEffectSensor_PIN); + sum += v; + cnt++; + delayMicroseconds(25); } - - int8_t HallEffectSensor::LastWaitForState() { - return lastWaitForState; + uint16_t av = sum / cnt; + // update statistic + if (av > maxVal) { + maxVal = av; + } + if (av < minVal) { + minVal = av; } + diffVal = maxVal - minVal; + calibrationProbes++; + if (doLog) { + Log_Printf(LOGLEVEL_INFO, "Read HallEffectSensor> value:%d", av); + } + return av; +}; + +bool HallEffectSensor::saveActualFieldValue2NVS() { + uint16_t sva = gHallEffectSensor.readSensorValueAverage(true); + bool res = SaveToNullFieldValueNVS(sva); + LoadNullFieldValueFromNVS(); + return res; +}; + +uint8_t HallEffectSensor::waitForState(uint16_t waitMS) { + // wait for magnetic north or south + lastWaitForState = 0; + unsigned long int startms = millis(); + ; + uint16_t sav; + do { + sav = readSensorValueAverage(true); + if (sav < nullFieldValue - HallEffectMinDiffValue) { + lastWaitForState = 1; + } else if (sav > nullFieldValue + HallEffectMinDiffValue) { + lastWaitForState = 2; + } else { + delay(50); + } + } while ((lastWaitForState == 0) && (millis() < (startms + waitMS))); + lastWaitForStateMS = millis() - startms; + Log_Printf(LOGLEVEL_INFO, "HallEffectSensor waitForState> fieldValue:%d => state:%d, (duration:%d ms)", sav, lastWaitForState, lastWaitForStateMS); + return lastWaitForState; +}; + +uint16_t HallEffectSensor::NullFieldValue() { + return nullFieldValue; +} + +int HallEffectSensor::LastWaitForStateMS() { + return lastWaitForStateMS; +} + +int8_t HallEffectSensor::LastWaitForState() { + return lastWaitForState; +} #endif diff --git a/src/HallEffectSensor.h b/src/HallEffectSensor.h index dfcd2235..bd5da2ca 100644 --- a/src/HallEffectSensor.h +++ b/src/HallEffectSensor.h @@ -1,12 +1,12 @@ #pragma once -#define HallEffectMinDiffValue 100 // I had a minimum change of 250, so reliable (factor 2.5) sensitive detection | Delta analog read max. +- 10 +#define HallEffectMinDiffValue 100 // I had a minimum change of 250, so reliable (factor 2.5) sensitive detection | Delta analog read max. +- 10 #define HallEffectMaxDiffValueReCalibrate 50 // Auto ReCalibration after start, when no HockeyDualfunctionTag is near reader -#define HallEffectAverageProbesMS 40 // average wird HallEffectAverageProbesMS milliseconds ermittelt -#define HallEffectWaitMS 750 // max. definable Value: 65.535 (uint16_t) affects responsetime, when normal Tag (no HockeyMagneticTag) is used, 1000 ms is a good value for me +#define HallEffectAverageProbesMS 40 // average wird HallEffectAverageProbesMS milliseconds ermittelt +#define HallEffectWaitMS 750 // max. definable Value: 65.535 (uint16_t) affects responsetime, when normal Tag (no HockeyMagneticTag) is used, 1000 ms is a good value for me class HallEffectSensor { - public: +public: HallEffectSensor(); void init(); void cyclic(); @@ -16,7 +16,7 @@ class HallEffectSensor { int8_t LastWaitForState(); uint16_t readSensorValueAverage(bool doLog); uint8_t waitForState(uint16_t waitMS); // 0=no magneticTag, 1=negativ magField, 2=positive magField - private: +private: // calibration static const uint16_t calibrationFctCallsPauseMS = 0; static const uint16_t maxCalibrationFctCalls = 1; diff --git a/src/IrReceiver.cpp b/src/IrReceiver.cpp index 4f5c21f9..2e50b1c3 100644 --- a/src/IrReceiver.cpp +++ b/src/IrReceiver.cpp @@ -1,6 +1,8 @@ #include #include "settings.h" + #include "IrReceiver.h" + #include "AudioPlayer.h" #include "Cmd.h" #include "Log.h" @@ -13,127 +15,127 @@ // HW-Timer #ifdef IR_CONTROL_ENABLE - uint32_t IrReceiver_LastRcCmdTimestamp = 0u; +uint32_t IrReceiver_LastRcCmdTimestamp = 0u; #endif void IrReceiver_Init() { - #ifdef IR_CONTROL_ENABLE - IrReceiver.begin(IRLED_PIN); - #endif +#ifdef IR_CONTROL_ENABLE + IrReceiver.begin(IRLED_PIN); +#endif } void IrReceiver_Cyclic() { - #ifdef IR_CONTROL_ENABLE - static uint8_t lastVolume = 0; +#ifdef IR_CONTROL_ENABLE + static uint8_t lastVolume = 0; - if (IrReceiver.decode()) { + if (IrReceiver.decode()) { - // Print a short summary of received data - IrReceiver.printIRResultShort(&Serial); - Serial.println(); - IrReceiver.resume(); // Enable receiving of the next value - bool rcActionOk = false; - if (millis() - IrReceiver_LastRcCmdTimestamp >= IR_DEBOUNCE) { - rcActionOk = true; // not used for volume up/down - IrReceiver_LastRcCmdTimestamp = millis(); - } + // Print a short summary of received data + IrReceiver.printIRResultShort(&Serial); + Serial.println(); + IrReceiver.resume(); // Enable receiving of the next value + bool rcActionOk = false; + if (millis() - IrReceiver_LastRcCmdTimestamp >= IR_DEBOUNCE) { + rcActionOk = true; // not used for volume up/down + IrReceiver_LastRcCmdTimestamp = millis(); + } - switch (IrReceiver.decodedIRData.command) { - case RC_PLAY: { - if (rcActionOk) { - Cmd_Action(CMD_PLAYPAUSE); - Log_Println("RC: Play", LOGLEVEL_NOTICE); - } - break; + switch (IrReceiver.decodedIRData.command) { + case RC_PLAY: { + if (rcActionOk) { + Cmd_Action(CMD_PLAYPAUSE); + Log_Println("RC: Play", LOGLEVEL_NOTICE); } - case RC_PAUSE: { - if (rcActionOk) { - Cmd_Action(CMD_PLAYPAUSE); - Log_Println("RC: Pause", LOGLEVEL_NOTICE); - } - break; - } - case RC_NEXT: { - if (rcActionOk) { - Cmd_Action(CMD_NEXTTRACK); - Log_Println("RC: Next", LOGLEVEL_NOTICE); - } - break; - } - case RC_PREVIOUS: { - if (rcActionOk) { - Cmd_Action(CMD_PREVTRACK); - Log_Println("RC: Previous", LOGLEVEL_NOTICE); - } - break; + break; + } + case RC_PAUSE: { + if (rcActionOk) { + Cmd_Action(CMD_PLAYPAUSE); + Log_Println("RC: Pause", LOGLEVEL_NOTICE); } - case RC_FIRST: { - if (rcActionOk) { - Cmd_Action(CMD_FIRSTTRACK); - Log_Println("RC: First", LOGLEVEL_NOTICE); - } - break; + break; + } + case RC_NEXT: { + if (rcActionOk) { + Cmd_Action(CMD_NEXTTRACK); + Log_Println("RC: Next", LOGLEVEL_NOTICE); } - case RC_LAST: { - if (rcActionOk) { - Cmd_Action(CMD_LASTTRACK); - Log_Println("RC: Last", LOGLEVEL_NOTICE); - } - break; + break; + } + case RC_PREVIOUS: { + if (rcActionOk) { + Cmd_Action(CMD_PREVTRACK); + Log_Println("RC: Previous", LOGLEVEL_NOTICE); } - case RC_MUTE: { - if (rcActionOk) { - if (AudioPlayer_GetCurrentVolume() > 0) { - lastVolume = AudioPlayer_GetCurrentVolume(); - AudioPlayer_SetCurrentVolume(0u); - } else { - AudioPlayer_SetCurrentVolume(lastVolume); // Remember last volume if mute is pressed again - } - - uint8_t currentVolume = AudioPlayer_GetCurrentVolume(); - xQueueSend(gVolumeQueue, ¤tVolume, 0); - Log_Println("RC: Mute", LOGLEVEL_NOTICE); - } - break; + break; + } + case RC_FIRST: { + if (rcActionOk) { + Cmd_Action(CMD_FIRSTTRACK); + Log_Println("RC: First", LOGLEVEL_NOTICE); } - case RC_BLUETOOTH: { - if (rcActionOk) { - Cmd_Action(CMD_TOGGLE_BLUETOOTH_SINK_MODE); - Log_Println("RC: Bluetooth sink", LOGLEVEL_NOTICE); - } - break; + break; + } + case RC_LAST: { + if (rcActionOk) { + Cmd_Action(CMD_LASTTRACK); + Log_Println("RC: Last", LOGLEVEL_NOTICE); } - // +++ todo: bluetooth source mode +++ - case RC_FTP: { - if (rcActionOk) { - Cmd_Action(CMD_ENABLE_FTP_SERVER); - Log_Println("RC: FTP", LOGLEVEL_NOTICE); + break; + } + case RC_MUTE: { + if (rcActionOk) { + if (AudioPlayer_GetCurrentVolume() > 0) { + lastVolume = AudioPlayer_GetCurrentVolume(); + AudioPlayer_SetCurrentVolume(0u); + } else { + AudioPlayer_SetCurrentVolume(lastVolume); // Remember last volume if mute is pressed again } - break; + + uint8_t currentVolume = AudioPlayer_GetCurrentVolume(); + xQueueSend(gVolumeQueue, ¤tVolume, 0); + Log_Println("RC: Mute", LOGLEVEL_NOTICE); } - case RC_SHUTDOWN: { - if (rcActionOk) { - System_RequestSleep(); - Log_Println("RC: Shutdown", LOGLEVEL_NOTICE); - } - break; + break; + } + case RC_BLUETOOTH: { + if (rcActionOk) { + Cmd_Action(CMD_TOGGLE_BLUETOOTH_SINK_MODE); + Log_Println("RC: Bluetooth sink", LOGLEVEL_NOTICE); } - case RC_VOL_DOWN: { - Cmd_Action(CMD_VOLUMEDOWN); - Log_Println("RC: Volume down", LOGLEVEL_NOTICE); - break; + break; + } + // +++ todo: bluetooth source mode +++ + case RC_FTP: { + if (rcActionOk) { + Cmd_Action(CMD_ENABLE_FTP_SERVER); + Log_Println("RC: FTP", LOGLEVEL_NOTICE); } - case RC_VOL_UP: { - Cmd_Action(CMD_VOLUMEUP); - Log_Println("RC: Volume up", LOGLEVEL_NOTICE); - break; + break; + } + case RC_SHUTDOWN: { + if (rcActionOk) { + System_RequestSleep(); + Log_Println("RC: Shutdown", LOGLEVEL_NOTICE); } - default: { - if (rcActionOk) { - Log_Println("RC: unknown", LOGLEVEL_NOTICE); - } + break; + } + case RC_VOL_DOWN: { + Cmd_Action(CMD_VOLUMEDOWN); + Log_Println("RC: Volume down", LOGLEVEL_NOTICE); + break; + } + case RC_VOL_UP: { + Cmd_Action(CMD_VOLUMEUP); + Log_Println("RC: Volume up", LOGLEVEL_NOTICE); + break; + } + default: { + if (rcActionOk) { + Log_Println("RC: unknown", LOGLEVEL_NOTICE); } } } - #endif + } +#endif } diff --git a/src/Led.cpp b/src/Led.cpp index c9039a12..f46f55cd 100644 --- a/src/Led.cpp +++ b/src/Led.cpp @@ -1,26 +1,29 @@ #include -#include -#include #include "settings.h" + +#include "Led.h" + #include "AudioPlayer.h" #include "Battery.h" +#include "Bluetooth.h" #include "Button.h" -#include "Led.h" #include "Log.h" +#include "Port.h" #include "System.h" #include "Wlan.h" -#include "Bluetooth.h" -#include "Port.h" + +#include +#include #ifdef NEOPIXEL_ENABLE #include - #define LED_INITIAL_BRIGHTNESS 16u + #define LED_INITIAL_BRIGHTNESS 16u #define LED_INITIAL_NIGHT_BRIGHTNESS 2u - #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))) + #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))) #ifndef LED_OFFSET #define LED_OFFSET 0 @@ -29,1091 +32,1087 @@ #endif // Time in milliseconds the volume indicator is visible - #define LED_VOLUME_INDICATOR_RETURN_DELAY 1000U - #define LED_VOLUME_INDICATOR_NUM_CYCLES (LED_VOLUME_INDICATOR_RETURN_DELAY / 20) - - extern t_button gButtons[7]; // next + prev + pplay + rotEnc + button4 + button5 + dummy-button - extern uint8_t gShutdownButton; - - static uint32_t Led_Indicators = 0u; - - static bool Led_Pause = false; // Used to pause Neopixel-signalisation (while NVS-writes as this leads to exceptions; don't know why) - - static uint8_t Led_InitialBrightness = LED_INITIAL_BRIGHTNESS; - static uint8_t Led_Brightness = LED_INITIAL_BRIGHTNESS; - static uint8_t Led_NightBrightness = LED_INITIAL_NIGHT_BRIGHTNESS; - constexpr uint8_t Led_IdleDotDistance = NUM_INDICATOR_LEDS / NUM_LEDS_IDLE_DOTS; - - static CRGBArray leds; - static CRGBSet indicator(leds(0, NUM_INDICATOR_LEDS - 1)); - static CRGBSet controlLeds(leds(NUM_INDICATOR_LEDS, NUM_INDICATOR_LEDS + NUM_CONTROL_LEDS - 1)); - - TaskHandle_t Led_TaskHandle; - static void Led_Task(void *parameter); - static uint8_t Led_Address(uint8_t number); - - // animation-functions prototypes - AnimationReturnType Animation_PlaylistProgress(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_BatteryMeasurement(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Volume(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Progress(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Boot(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Shutdown(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Error(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Ok(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_VoltageWarning(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Webstream(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Rewind(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Idle(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Busy(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Pause(const bool startNewAnimation, CRGBSet &leds); - AnimationReturnType Animation_Speech(const bool startNewAnimation, CRGBSet &leds); + #define LED_VOLUME_INDICATOR_RETURN_DELAY 1000U + #define LED_VOLUME_INDICATOR_NUM_CYCLES (LED_VOLUME_INDICATOR_RETURN_DELAY / 20) + +extern t_button gButtons[7]; // next + prev + pplay + rotEnc + button4 + button5 + dummy-button +extern uint8_t gShutdownButton; + +static uint32_t Led_Indicators = 0u; + +static bool Led_Pause = false; // Used to pause Neopixel-signalisation (while NVS-writes as this leads to exceptions; don't know why) + +static uint8_t Led_InitialBrightness = LED_INITIAL_BRIGHTNESS; +static uint8_t Led_Brightness = LED_INITIAL_BRIGHTNESS; +static uint8_t Led_NightBrightness = LED_INITIAL_NIGHT_BRIGHTNESS; +constexpr uint8_t Led_IdleDotDistance = NUM_INDICATOR_LEDS / NUM_LEDS_IDLE_DOTS; + +static CRGBArray leds; +static CRGBSet indicator(leds(0, NUM_INDICATOR_LEDS - 1)); +static CRGBSet controlLeds(leds(NUM_INDICATOR_LEDS, NUM_INDICATOR_LEDS + NUM_CONTROL_LEDS - 1)); + +TaskHandle_t Led_TaskHandle; +static void Led_Task(void *parameter); +static uint8_t Led_Address(uint8_t number); + +// animation-functions prototypes +AnimationReturnType Animation_PlaylistProgress(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_BatteryMeasurement(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Volume(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Progress(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Boot(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Shutdown(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Error(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Ok(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_VoltageWarning(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Webstream(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Rewind(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Idle(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Busy(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Pause(const bool startNewAnimation, CRGBSet &leds); +AnimationReturnType Animation_Speech(const bool startNewAnimation, CRGBSet &leds); #endif void Led_Init(void) { - #ifdef NEOPIXEL_ENABLE - // Get some stuff from NVS... - // Get initial LED-brightness from NVS - uint8_t nvsILedBrightness = gPrefsSettings.getUChar("iLedBrightness", 0); - if (nvsILedBrightness) { - Led_InitialBrightness = nvsILedBrightness; - Led_Brightness = nvsILedBrightness; - Log_Printf(LOGLEVEL_INFO, initialBrightnessfromNvs, nvsILedBrightness); - } else { - gPrefsSettings.putUChar("iLedBrightness", Led_InitialBrightness); - Log_Println(wroteInitialBrightnessToNvs, LOGLEVEL_ERROR); - } +#ifdef NEOPIXEL_ENABLE + // Get some stuff from NVS... + // Get initial LED-brightness from NVS + uint8_t nvsILedBrightness = gPrefsSettings.getUChar("iLedBrightness", 0); + if (nvsILedBrightness) { + Led_InitialBrightness = nvsILedBrightness; + Led_Brightness = nvsILedBrightness; + Log_Printf(LOGLEVEL_INFO, initialBrightnessfromNvs, nvsILedBrightness); + } else { + gPrefsSettings.putUChar("iLedBrightness", Led_InitialBrightness); + Log_Println(wroteInitialBrightnessToNvs, LOGLEVEL_ERROR); + } - // Get night LED-brightness from NVS - uint8_t nvsNLedBrightness = gPrefsSettings.getUChar("nLedBrightness", 255); - if (nvsNLedBrightness != 255) { - Led_NightBrightness = nvsNLedBrightness; - Log_Printf(LOGLEVEL_INFO, restoredInitialBrightnessForNmFromNvs, nvsNLedBrightness); - } else { - gPrefsSettings.putUChar("nLedBrightness", Led_NightBrightness); - Log_Println(wroteNmBrightnessToNvs, LOGLEVEL_ERROR); - } + // Get night LED-brightness from NVS + uint8_t nvsNLedBrightness = gPrefsSettings.getUChar("nLedBrightness", 255); + if (nvsNLedBrightness != 255) { + Led_NightBrightness = nvsNLedBrightness; + Log_Printf(LOGLEVEL_INFO, restoredInitialBrightnessForNmFromNvs, nvsNLedBrightness); + } else { + gPrefsSettings.putUChar("nLedBrightness", Led_NightBrightness); + Log_Println(wroteNmBrightnessToNvs, LOGLEVEL_ERROR); + } - xTaskCreatePinnedToCore( - Led_Task, /* Function to implement the task */ - "Led_Task", /* Name of the task */ - 1512, /* 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 + xTaskCreatePinnedToCore( + Led_Task, /* Function to implement the task */ + "Led_Task", /* Name of the task */ + 1512, /* 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 +#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 } void Led_Indicate(LedIndicatorType value) { - #ifdef NEOPIXEL_ENABLE - LED_INDICATOR_SET(value); - #endif +#ifdef NEOPIXEL_ENABLE + LED_INDICATOR_SET(value); +#endif } void Led_SetPause(boolean value) { - #ifdef NEOPIXEL_ENABLE - Led_Pause = value; - #endif +#ifdef NEOPIXEL_ENABLE + Led_Pause = value; +#endif } // Used to reset brightness to initial value after prevously active sleepmode was left void Led_ResetToInitialBrightness(void) { - #ifdef NEOPIXEL_ENABLE - if (Led_Brightness == Led_NightBrightness || Led_Brightness == 0) { // Only reset to initial value if brightness wasn't intentionally changed (or was zero) - Led_Brightness = Led_InitialBrightness; - Log_Println(ledsDimmedToInitialValue, LOGLEVEL_INFO); - } - #endif - #ifdef BUTTONS_LED - Port_Write(BUTTONS_LED, HIGH, false); - #endif +#ifdef NEOPIXEL_ENABLE + if (Led_Brightness == Led_NightBrightness || Led_Brightness == 0) { // Only reset to initial value if brightness wasn't intentionally changed (or was zero) + Led_Brightness = Led_InitialBrightness; + Log_Println(ledsDimmedToInitialValue, LOGLEVEL_INFO); + } +#endif +#ifdef BUTTONS_LED + Port_Write(BUTTONS_LED, HIGH, false); +#endif } void Led_ResetToNightBrightness(void) { - #ifdef NEOPIXEL_ENABLE - Led_Brightness = Led_NightBrightness; - Log_Println(ledsDimmedToNightmode, LOGLEVEL_INFO); - #endif - #ifdef BUTTONS_LED - Port_Write(BUTTONS_LED, LOW, false); - #endif +#ifdef NEOPIXEL_ENABLE + Led_Brightness = Led_NightBrightness; + Log_Println(ledsDimmedToNightmode, LOGLEVEL_INFO); +#endif +#ifdef BUTTONS_LED + Port_Write(BUTTONS_LED, LOW, false); +#endif } uint8_t Led_GetBrightness(void) { - #ifdef NEOPIXEL_ENABLE - return Led_Brightness; - #else - return 0u; - #endif +#ifdef NEOPIXEL_ENABLE + return Led_Brightness; +#else + return 0u; +#endif } void Led_SetBrightness(uint8_t value) { - #ifdef NEOPIXEL_ENABLE - Led_Brightness = value; - #ifdef BUTTONS_LED - Port_Write(BUTTONS_LED, value <= Led_NightBrightness ? LOW : HIGH, false); - #endif +#ifdef NEOPIXEL_ENABLE + Led_Brightness = value; + #ifdef BUTTONS_LED + Port_Write(BUTTONS_LED, value <= Led_NightBrightness ? LOW : HIGH, false); #endif +#endif } // Calculates physical address for a virtual LED address. This handles reversing the rotation direction of the ring and shifting the starting LED #ifdef NEOPIXEL_ENABLE - uint8_t Led_Address(uint8_t number) { - #ifdef NEOPIXEL_REVERSE_ROTATION - #if LED_OFFSET > 0 - return number <= LED_OFFSET - 1 ? LED_OFFSET - 1 - number : NUM_INDICATOR_LEDS + LED_OFFSET - 1 - number; - #else - return NUM_INDICATOR_LEDS - 1 - number; - #endif +uint8_t Led_Address(uint8_t number) { + #ifdef NEOPIXEL_REVERSE_ROTATION + #if LED_OFFSET > 0 + return number <= LED_OFFSET - 1 ? LED_OFFSET - 1 - number : NUM_INDICATOR_LEDS + LED_OFFSET - 1 - number; #else - #if LED_OFFSET > 0 - return number >= NUM_INDICATOR_LEDS - LED_OFFSET ? number + LED_OFFSET - NUM_INDICATOR_LEDS : number + LED_OFFSET; - #else - return number; - #endif + return NUM_INDICATOR_LEDS - 1 - number; #endif - } + #else + #if LED_OFFSET > 0 + return number >= NUM_INDICATOR_LEDS - LED_OFFSET ? number + LED_OFFSET - NUM_INDICATOR_LEDS : number + LED_OFFSET; + #else + return number; + #endif + #endif +} #endif #ifdef NEOPIXEL_ENABLE - void Led_DrawControls() { - #if NUM_CONTROL_LEDS > 0 - static CRGB::HTMLColorCode controlLedColors[NUM_CONTROL_LEDS] = CONTROL_LEDS_COLORS; - for (uint8_t controlLed = 0; controlLed < NUM_CONTROL_LEDS; controlLed++) { - controlLeds[controlLed] = controlLedColors[controlLed]; - } - #endif +void Led_DrawControls() { + #if NUM_CONTROL_LEDS > 0 + static CRGB::HTMLColorCode controlLedColors[NUM_CONTROL_LEDS] = CONTROL_LEDS_COLORS; + for (uint8_t controlLed = 0; controlLed < NUM_CONTROL_LEDS; controlLed++) { + controlLeds[controlLed] = controlLedColors[controlLed]; } + #endif +} #endif void Led_SetButtonLedsEnabled(boolean value) { - #ifdef BUTTONS_LED - Port_Write(BUTTONS_LED, value ? HIGH : LOW, false); - #endif +#ifdef BUTTONS_LED + Port_Write(BUTTONS_LED, value ? HIGH : LOW, false); +#endif } - #ifdef NEOPIXEL_ENABLE - CRGB Led_DimColor(CRGB color, uint8_t brightness) { - const uint8_t factor = uint16_t(brightness * __UINT8_MAX__) / DIMMABLE_STATES; - return color.nscale8(factor); - } - CRGB::HTMLColorCode Led_GetIdleColor() { - CRGB::HTMLColorCode idleColor = CRGB::Black; - if ((OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { - if (Bluetooth_Device_Connected()) { - idleColor = CRGB::Blue; - } else { - idleColor = CRGB::BlueViolet; - } +CRGB Led_DimColor(CRGB color, uint8_t brightness) { + const uint8_t factor = uint16_t(brightness * __UINT8_MAX__) / DIMMABLE_STATES; + return color.nscale8(factor); +} +CRGB::HTMLColorCode Led_GetIdleColor() { + CRGB::HTMLColorCode idleColor = CRGB::Black; + if ((OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) || (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode())) { + if (Bluetooth_Device_Connected()) { + idleColor = CRGB::Blue; } else { - if (Wlan_ConnectionTryInProgress()) { - idleColor = CRGB::Orange; - } else { - idleColor = CRGB::Green; - if (Wlan_IsConnected()) { - idleColor = CRGB::White; - } + idleColor = CRGB::BlueViolet; + } + } else { + if (Wlan_ConnectionTryInProgress()) { + idleColor = CRGB::Orange; + } else { + idleColor = CRGB::Green; + if (Wlan_IsConnected()) { + idleColor = CRGB::White; } } - return idleColor; } + return idleColor; +} - void Led_DrawIdleDots(CRGBSet &leds, uint8_t offset, CRGB::HTMLColorCode color) { - for (uint8_t i=0; i= 150) && gButtonInitComplete) { - return true; - } +bool CheckForPowerButtonAnimation() { + if (gShutdownButton < (sizeof(gButtons) / sizeof(gButtons[0])) - 1) { // Only show animation, if CMD_SLEEPMODE was assigned to BUTTON_n_LONG + button is pressed + if (gButtons[gShutdownButton].isPressed && (millis() - gButtons[gShutdownButton].firstPressedTimestamp >= 150) && gButtonInitComplete) { + return true; } - return false; } + return false; +} #endif #ifdef NEOPIXEL_ENABLE - static void Led_Task(void *parameter) { - static uint8_t lastLedBrightness = Led_Brightness; - FastLED.addLeds(leds, leds.size()).setCorrection(TypicalSMD5050); - FastLED.setBrightness(Led_Brightness); - FastLED.setDither(DISABLE_DITHER); - - LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; - LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; - bool animationActive = false; - int32_t animationTimer = 0; - - for (;;) { - // special handling - if (Led_Pause) { // Workaround to prevent exceptions while NVS-writes take place - vTaskDelay(portTICK_PERIOD_MS * 10); - continue; - } +static void Led_Task(void *parameter) { + static uint8_t lastLedBrightness = Led_Brightness; + FastLED.addLeds(leds, leds.size()).setCorrection(TypicalSMD5050); + FastLED.setBrightness(Led_Brightness); + FastLED.setDither(DISABLE_DITHER); + + LedAnimationType activeAnimation = LedAnimationType::NoNewAnimation; + LedAnimationType nextAnimation = LedAnimationType::NoNewAnimation; + bool animationActive = false; + int32_t animationTimer = 0; + + for (;;) { + // special handling + if (Led_Pause) { // Workaround to prevent exceptions while NVS-writes take place + vTaskDelay(portTICK_PERIOD_MS * 10); + continue; + } - Led_DrawControls(); - - 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.isWebstream) { // also animate pause in the webstream animation - nextAnimation = LedAnimationType::Webstream; - } else if ((gPlayProperties.playMode != BUSY) && (gPlayProperties.playMode != NO_PLAYLIST)) { - nextAnimation = LedAnimationType::Progress; - } 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(); + + 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.isWebstream) { // also animate pause in the webstream animation + nextAnimation = LedAnimationType::Webstream; + } else if ((gPlayProperties.playMode != BUSY) && (gPlayProperties.playMode != NO_PLAYLIST)) { + nextAnimation = LedAnimationType::Progress; + } 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 != Led_Brightness) { - FastLED.setBrightness(Led_Brightness); - lastLedBrightness = Led_Brightness; - } + // apply brightness-changes + if (lastLedBrightness != Led_Brightness) { + FastLED.setBrightness(Led_Brightness); + lastLedBrightness = 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; - FastLED.show(); - ret.animationActive = false; - ret.animationDelay = 50; + // 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; - } - // apply delay and state from animation - animationActive = ret.animationActive; - animationTimer = ret.animationDelay; - if(ret.animationRefresh) { + + 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; + if (ret.animationRefresh) { + FastLED.show(); } - animationTimer -= taskDelay; - vTaskDelay(portTICK_PERIOD_MS * taskDelay); } - vTaskDelete(NULL); + + // get the time to wait and delay the task + if ((animationTimer > 0) && (animationTimer < taskDelay)) { + taskDelay = animationTimer; + } + animationTimer -= taskDelay; + vTaskDelay(portTICK_PERIOD_MS * taskDelay); } + vTaskDelete(NULL); +} #endif #ifdef NEOPIXEL_ENABLE - // --------------------------------------------------------------------- - // --------------- ANIMATION-METHODS --------------------- - // --------------------------------------------------------------------- - // * each function has to be non-blocking. - // * all states are kept in this function. - // * all funcitons return the desired delay and if they are still active - // * the function will be called the next time when the returned delay has - // passed - // * the optional Start Flag signals that the animation is started new - - - // -------------------------------- - // BOOT-UP Animation - // -------------------------------- - AnimationReturnType Animation_Boot(const bool startNewAnimation, CRGBSet &leds) { - (void)startNewAnimation; // start is not used - // static vars - static bool showEvenError = false; - - // 10 s without success? - if (millis() > 10000) { - leds = CRGB::Red; - if (showEvenError) { - // and then draw in the black dots - for (uint8_t i=0;i 10000) { + leds = CRGB::Red; + if (showEvenError) { + // and then draw in the black dots + for (uint8_t i = 0; i < leds.size(); i += 2) { + leds[i] = CRGB::Black; } } - showEvenError = !showEvenError; - - return AnimationReturnType(false, 500, true); // always wait 500 ms + } else { + leds = CRGB::Black; + const uint8_t startLed = (showEvenError) ? 1 : 0; + for (uint8_t i = startLed; i < leds.size(); i += 2) { + leds[i] = CRGB::Orange; + } } + showEvenError = !showEvenError; - // -------------------------------- - // Shutdown Animation - // -------------------------------- - AnimationReturnType Animation_Shutdown(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = true; - int32_t animationDelay = 0; - // static vars - static bool singleLedStatus = false; - static uint32_t animationIndex = 0; - if (startNewAnimation) { - animationIndex = 0; - } + return AnimationReturnType(false, 500, true); // always wait 500 ms +} - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds = CRGB::Black; - if (millis() - gButtons[gShutdownButton].firstPressedTimestamp <= intervalToLongPress) { - leds[0] = CRGB::Red; - animationDelay = 5; - } else { - if (singleLedStatus) { - leds[0] = CRGB::Red; - } - singleLedStatus = !singleLedStatus; - animationDelay = 50; - } - animationActive = false; - } else { - if ((millis() - gButtons[gShutdownButton].firstPressedTimestamp >= intervalToLongPress) && (animationIndex >= leds.size())) { - animationDelay = 50; - if (!gButtons[gShutdownButton].isPressed) { - // increase animation index to bail out, if we had a kombi-button - animationIndex++; - if (animationIndex >= leds.size() + 3) { - animationActive = false; // this is approx. 150ms after the button is released - } - } - } else { - if (animationIndex == 0) { - leds = CRGB::Black; - } - if (animationIndex < leds.size()) { - leds[Led_Address(animationIndex)] = CRGB::Red; - if (gButtons[gShutdownButton].currentState) { - animationDelay = 5; - animationActive = false; - } else { - animationDelay = intervalToLongPress / leds.size(); - } - animationIndex++; - } - } - } - return AnimationReturnType(animationActive, animationDelay, true); +// -------------------------------- +// Shutdown Animation +// -------------------------------- +AnimationReturnType Animation_Shutdown(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = true; + int32_t animationDelay = 0; + // static vars + static bool singleLedStatus = false; + static uint32_t animationIndex = 0; + if (startNewAnimation) { + animationIndex = 0; } - // -------------------------------- - // Error Animation - // -------------------------------- - AnimationReturnType Animation_Error(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = true; - uint16_t animationDelay = 0; - // static vars - static bool singleLedStatus = false; - static uint16_t animationIndex = 0; - if (startNewAnimation) { - animationIndex = 0; - } - - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds = CRGB::Black; + if constexpr (NUM_INDICATOR_LEDS == 1) { + leds = CRGB::Black; + if (millis() - gButtons[gShutdownButton].firstPressedTimestamp <= intervalToLongPress) { + leds[0] = CRGB::Red; + animationDelay = 5; + } else { if (singleLedStatus) { leds[0] = CRGB::Red; } singleLedStatus = !singleLedStatus; - - if (animationIndex < 5) { + animationDelay = 50; + } + animationActive = false; + } else { + if ((millis() - gButtons[gShutdownButton].firstPressedTimestamp >= intervalToLongPress) && (animationIndex >= leds.size())) { + animationDelay = 50; + if (!gButtons[gShutdownButton].isPressed) { + // increase animation index to bail out, if we had a kombi-button animationIndex++; - animationDelay = 100; - } else { - animationActive = false; + if (animationIndex >= leds.size() + 3) { + animationActive = false; // this is approx. 150ms after the button is released + } } } else { - leds = CRGB::Red; - if (animationIndex > 0) { - animationActive = false; - } else { + if (animationIndex == 0) { + leds = CRGB::Black; + } + if (animationIndex < leds.size()) { + leds[Led_Address(animationIndex)] = CRGB::Red; + if (gButtons[gShutdownButton].currentState) { + animationDelay = 5; + animationActive = false; + } else { + animationDelay = intervalToLongPress / leds.size(); + } animationIndex++; - animationDelay = 200; } } - return AnimationReturnType(animationActive, animationDelay, true); } - // -------------------------------- - // OK Animation - // -------------------------------- - AnimationReturnType Animation_Ok(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = true; - uint16_t animationDelay = 0; - // static vars - static bool singleLedStatus = false; - static uint16_t animationIndex = 0; - if (startNewAnimation) { - animationIndex = 0; - } + return AnimationReturnType(animationActive, animationDelay, true); +} - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds = CRGB::Black; - if (singleLedStatus) { - leds[0] = CRGB::Green; - } - singleLedStatus = !singleLedStatus; +// -------------------------------- +// Error Animation +// -------------------------------- +AnimationReturnType Animation_Error(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = true; + uint16_t animationDelay = 0; + // static vars + static bool singleLedStatus = false; + static uint16_t animationIndex = 0; + if (startNewAnimation) { + animationIndex = 0; + } - if (animationIndex < 5) { - animationIndex++; - animationDelay = 100; - } else { - animationActive = false; - } - } else { - leds = CRGB::Green; - if (animationIndex > 0) { - animationActive = false; - } else { - animationIndex++; - animationDelay = 400; - } + if constexpr (NUM_INDICATOR_LEDS == 1) { + leds = CRGB::Black; + if (singleLedStatus) { + leds[0] = CRGB::Red; } - return AnimationReturnType(animationActive, animationDelay, true); - } + singleLedStatus = !singleLedStatus; - // -------------------------------- - // VoltageWarning Animation - // -------------------------------- - // Single + Multiple LEDs: flashes red three times if battery-voltage is low - AnimationReturnType Animation_VoltageWarning(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = true; - uint16_t animationDelay = 0; - // static vars - static uint16_t animationIndex = 0; - - if (startNewAnimation) { - animationIndex = 0; + if (animationIndex < 5) { + animationIndex++; + animationDelay = 100; + } else { + animationActive = false; + } + } else { + leds = CRGB::Red; + if (animationIndex > 0) { + animationActive = false; + } else { + animationIndex++; + animationDelay = 200; } + } + return AnimationReturnType(animationActive, animationDelay, true); +} +// -------------------------------- +// OK Animation +// -------------------------------- +AnimationReturnType Animation_Ok(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = true; + uint16_t animationDelay = 0; + // static vars + static bool singleLedStatus = false; + static uint16_t animationIndex = 0; + if (startNewAnimation) { + animationIndex = 0; + } + if constexpr (NUM_INDICATOR_LEDS == 1) { leds = CRGB::Black; - if (animationIndex % 2 == 0) { - leds = CRGB::Red; + if (singleLedStatus) { + leds[0] = CRGB::Green; } + singleLedStatus = !singleLedStatus; - if (animationIndex < 6) { + if (animationIndex < 5) { animationIndex++; - animationDelay = 200; + animationDelay = 100; } else { animationActive = false; } - return AnimationReturnType(animationActive, animationDelay, true); + } else { + leds = CRGB::Green; + if (animationIndex > 0) { + animationActive = false; + } else { + animationIndex++; + animationDelay = 400; + } + } + return AnimationReturnType(animationActive, animationDelay, true); +} + +// -------------------------------- +// VoltageWarning Animation +// -------------------------------- +// Single + Multiple LEDs: flashes red three times if battery-voltage is low +AnimationReturnType Animation_VoltageWarning(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = true; + uint16_t animationDelay = 0; + // static vars + static uint16_t animationIndex = 0; + + if (startNewAnimation) { + animationIndex = 0; + } + + leds = CRGB::Black; + if (animationIndex % 2 == 0) { + leds = CRGB::Red; } - // -------------------------------- - // Webstream Animation - // -------------------------------- - // Animates the progress and Pause of a Webstream - AnimationReturnType Animation_Webstream(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = false; - bool refresh = false; - int32_t animationDelay = 0; - // static vars - static uint8_t ledPosWebstream = 0; - static uint8_t webstreamColor = 0; - static uint16_t timerProgress = 0; - - // pause-animation - if (gPlayProperties.pausePlay) { + if (animationIndex < 6) { + animationIndex++; + animationDelay = 200; + } else { + animationActive = false; + } + return AnimationReturnType(animationActive, animationDelay, true); +} + +// -------------------------------- +// Webstream Animation +// -------------------------------- +// Animates the progress and Pause of a Webstream +AnimationReturnType Animation_Webstream(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = false; + bool refresh = false; + int32_t animationDelay = 0; + // static vars + static uint8_t ledPosWebstream = 0; + static uint8_t webstreamColor = 0; + static uint16_t timerProgress = 0; + + // pause-animation + if (gPlayProperties.pausePlay) { + leds = CRGB::Black; + CRGB::HTMLColorCode generalColor = CRGB::Orange; + if (OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) { + generalColor = CRGB::Blue; + } + if constexpr (NUM_INDICATOR_LEDS == 1) { + leds[0] = generalColor; + } else { + leds[Led_Address(ledPosWebstream)] = generalColor; + leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()] = generalColor; + } + animationDelay = 10; + timerProgress = 0; // directly show new animation after pause + refresh = true; + } else { + if (startNewAnimation || timerProgress == 0) { leds = CRGB::Black; - CRGB::HTMLColorCode generalColor = CRGB::Orange; - if (OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) { - generalColor = CRGB::Blue; - } - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds[0] = generalColor; + timerProgress = 100; + if (ledPosWebstream + 1 < leds.size()) { + ledPosWebstream++; } else { - leds[Led_Address(ledPosWebstream)] = generalColor; - leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()] = generalColor; + ledPosWebstream = 0; } - animationDelay = 10; - timerProgress = 0; // directly show new animation after pause - refresh = true; - } else { - if (startNewAnimation || timerProgress == 0) { - leds = CRGB::Black; - timerProgress = 100; - if (ledPosWebstream + 1 < leds.size()) { - ledPosWebstream++; - } else { - ledPosWebstream = 0; + if (System_AreControlsLocked()) { + leds[Led_Address(ledPosWebstream)] = CRGB::Red; + if constexpr (NUM_INDICATOR_LEDS > 1) { + leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()] = CRGB::Red; } - if (System_AreControlsLocked()) { - leds[Led_Address(ledPosWebstream)] = CRGB::Red; - if constexpr(NUM_INDICATOR_LEDS > 1) { - leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()] = CRGB::Red; - } + } else { + if constexpr (NUM_INDICATOR_LEDS == 1) { + leds[0].setHue(webstreamColor++); } else { - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds[0].setHue(webstreamColor++); + if (OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) { + leds[Led_Address(ledPosWebstream)] = CRGB::Blue; + leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()] = CRGB::Blue; } else { - if (OPMODE_BLUETOOTH_SINK == System_GetOperationMode()) { - leds[Led_Address(ledPosWebstream)] = CRGB::Blue; - leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()] = CRGB::Blue; - } else { - leds[Led_Address(ledPosWebstream)].setHue(webstreamColor); - leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()].setHue(webstreamColor++); - } + leds[Led_Address(ledPosWebstream)].setHue(webstreamColor); + leds[(Led_Address(ledPosWebstream) + leds.size() / 2) % leds.size()].setHue(webstreamColor++); } } - refresh = true; } - timerProgress --; - animationDelay = 45; - if (timerProgress > 0) { - animationActive = true; - } - } - return AnimationReturnType(animationActive, animationDelay, refresh); - } - - // -------------------------------- - // Rewind Animation - // -------------------------------- - AnimationReturnType Animation_Rewind(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = false; - bool refresh = false; - int32_t animationDelay = 0; - // static vars - static uint16_t animationIndex = 0; - if (startNewAnimation) { - animationIndex = 0; + refresh = true; } - - if constexpr(NUM_INDICATOR_LEDS >= 4) { + timerProgress--; + animationDelay = 45; + if (timerProgress > 0) { animationActive = true; - - if (animationIndex < (leds.size())) { - leds[Led_Address(leds.size() - 1 - animationIndex)] = CRGB::Black; - refresh = true; - animationDelay = 30; - animationIndex ++; - } else { - animationActive = false; - } } - return AnimationReturnType(animationActive, animationDelay, refresh); } + return AnimationReturnType(animationActive, animationDelay, refresh); +} - // -------------------------------- - // Idle Animation - // -------------------------------- - AnimationReturnType Animation_Idle(const bool startNewAnimation, CRGBSet &leds) { - // return values - int32_t animationDelay = 0; - bool animationActive = true; - bool refresh = true; - // static vars - static int16_t ledIndex = 0; - // this can be removed to always continue on the last position in idle - if (startNewAnimation) { - ledIndex = 0; - } +// -------------------------------- +// Rewind Animation +// -------------------------------- +AnimationReturnType Animation_Rewind(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = false; + bool refresh = false; + int32_t animationDelay = 0; + // static vars + static uint16_t animationIndex = 0; + if (startNewAnimation) { + animationIndex = 0; + } - if (ledIndex < leds.size()) { - CRGB::HTMLColorCode idleColor = Led_GetIdleColor(); - leds = CRGB::Black; - Led_DrawIdleDots(leds, ledIndex, idleColor); - animationDelay = 50*10; - ledIndex++; + if constexpr (NUM_INDICATOR_LEDS >= 4) { + animationActive = true; + + if (animationIndex < (leds.size())) { + leds[Led_Address(leds.size() - 1 - animationIndex)] = CRGB::Black; + refresh = true; + animationDelay = 30; + animationIndex++; } else { animationActive = false; - refresh = false; - ledIndex = 0; } - return AnimationReturnType(animationActive, animationDelay, refresh); } + return AnimationReturnType(animationActive, animationDelay, refresh); +} - // -------------------------------- - // Busy Animation - // -------------------------------- - AnimationReturnType Animation_Busy(const bool startNewAnimation, CRGBSet &leds) { - // return values - bool animationActive = true; - int32_t animationDelay = 0; - // static vars - static bool singleLedStatus = false; - static uint16_t animationIndex = 0; - if (startNewAnimation) { - animationIndex = 0; - } - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds = CRGB::Black; - singleLedStatus = !singleLedStatus; - if (singleLedStatus) { - leds[0] = CRGB::BlueViolet; - } - animationDelay = 100; - animationActive = false; - } else { - if (animationIndex < leds.size()) { - leds = CRGB::Black; - CRGB::HTMLColorCode idleColor = Led_GetIdleColor(); - Led_DrawIdleDots(leds, animationIndex, idleColor); - animationDelay = 50; - animationIndex++; - } else { - animationActive = false; - } - } - return AnimationReturnType(animationActive, animationDelay, true); +// -------------------------------- +// Idle Animation +// -------------------------------- +AnimationReturnType Animation_Idle(const bool startNewAnimation, CRGBSet &leds) { + // return values + int32_t animationDelay = 0; + bool animationActive = true; + bool refresh = true; + // static vars + static int16_t ledIndex = 0; + // this can be removed to always continue on the last position in idle + if (startNewAnimation) { + ledIndex = 0; } - // -------------------------------- - // Pause Animation - // -------------------------------- - // Animates the pause if no Webstream is active - AnimationReturnType Animation_Pause(const bool startNewAnimation, CRGBSet &leds) { - (void)startNewAnimation; // start is not used + if (ledIndex < leds.size()) { + CRGB::HTMLColorCode idleColor = Led_GetIdleColor(); + leds = CRGB::Black; + Led_DrawIdleDots(leds, ledIndex, idleColor); + animationDelay = 50 * 10; + ledIndex++; + } else { + animationActive = false; + refresh = false; + ledIndex = 0; + } + return AnimationReturnType(animationActive, animationDelay, refresh); +} +// -------------------------------- +// Busy Animation +// -------------------------------- +AnimationReturnType Animation_Busy(const bool startNewAnimation, CRGBSet &leds) { + // return values + bool animationActive = true; + int32_t animationDelay = 0; + // static vars + static bool singleLedStatus = false; + static uint16_t animationIndex = 0; + if (startNewAnimation) { + animationIndex = 0; + } + if constexpr (NUM_INDICATOR_LEDS == 1) { leds = CRGB::Black; - CRGB::HTMLColorCode generalColor = CRGB::Orange; - if (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode()) { - generalColor = CRGB::Blue; + singleLedStatus = !singleLedStatus; + if (singleLedStatus) { + leds[0] = CRGB::BlueViolet; } - - uint8_t pauseOffset = 0; - if (OFFSET_PAUSE_LEDS) { - pauseOffset = ((leds.size()/NUM_LEDS_IDLE_DOTS)/2)-1; + animationDelay = 100; + animationActive = false; + } else { + if (animationIndex < leds.size()) { + leds = CRGB::Black; + CRGB::HTMLColorCode idleColor = Led_GetIdleColor(); + Led_DrawIdleDots(leds, animationIndex, idleColor); + animationDelay = 50; + animationIndex++; + } else { + animationActive = false; } - Led_DrawIdleDots(leds, pauseOffset, generalColor); - - return AnimationReturnType(false, 10, true); } + return AnimationReturnType(animationActive, animationDelay, true); +} - // -------------------------------- - // Speech Animation - // -------------------------------- - // only draw yellow pause-dots - AnimationReturnType Animation_Speech(const bool startNewAnimation, CRGBSet &leds) { - (void)startNewAnimation; // start is not used - - leds = CRGB::Black; - uint8_t pauseOffset = 0; - if (OFFSET_PAUSE_LEDS) { - pauseOffset = ((leds.size()/NUM_LEDS_IDLE_DOTS)/2)-1; - } - Led_DrawIdleDots(leds, pauseOffset, CRGB::Yellow); +// -------------------------------- +// Pause Animation +// -------------------------------- +// Animates the pause if no Webstream is active +AnimationReturnType Animation_Pause(const bool startNewAnimation, CRGBSet &leds) { + (void) startNewAnimation; // start is not used + + leds = CRGB::Black; + CRGB::HTMLColorCode generalColor = CRGB::Orange; + if (OPMODE_BLUETOOTH_SOURCE == System_GetOperationMode()) { + generalColor = CRGB::Blue; + } - return AnimationReturnType(false, 10, true); + uint8_t pauseOffset = 0; + if (OFFSET_PAUSE_LEDS) { + pauseOffset = ((leds.size() / NUM_LEDS_IDLE_DOTS) / 2) - 1; } + Led_DrawIdleDots(leds, pauseOffset, generalColor); - // -------------------------------- - // Progress in Track Animation - // -------------------------------- - AnimationReturnType Animation_Progress(const bool startNewAnimation, CRGBSet &leds) { - // return values - int32_t animationDelay = 0; - // static values - static double lastPos = 0.0f; - - if (gPlayProperties.currentRelPos != lastPos || startNewAnimation) { - lastPos = gPlayProperties.currentRelPos; - leds = CRGB::Black; - if constexpr(NUM_INDICATOR_LEDS == 1) { - leds[0].setHue((uint8_t)(85 - ((double)90 / 100) * gPlayProperties.currentRelPos)); - } else { - const uint32_t ledValue = std::clamp(map(gPlayProperties.currentRelPos, 0, 98, 0, leds.size() * DIMMABLE_STATES), 0, leds.size() * DIMMABLE_STATES); - const uint8_t fullLeds = ledValue / DIMMABLE_STATES; - const uint8_t lastLed = ledValue % DIMMABLE_STATES; - for (uint8_t led = 0; led < fullLeds; led++) { - if (System_AreControlsLocked()) { - leds[Led_Address(led)] = CRGB::Red; - } else if (!gPlayProperties.pausePlay) { // Hue-rainbow - leds[Led_Address(led)].setHue((uint8_t)(((float)PROGRESS_HUE_END - (float)PROGRESS_HUE_START) / (leds.size()-1) * led + PROGRESS_HUE_START)); - } - } - if (lastLed > 0) { - if (System_AreControlsLocked()) { - leds[Led_Address(fullLeds)] = CRGB::Red; - } else { - leds[Led_Address(fullLeds)].setHue((uint8_t)(((float)PROGRESS_HUE_END - (float)PROGRESS_HUE_START) / (leds.size()-1) * fullLeds + PROGRESS_HUE_START)); - } - leds[Led_Address(fullLeds)] = Led_DimColor(leds[Led_Address(fullLeds)], lastLed); - } - } - animationDelay = 10; - } - return AnimationReturnType(false, animationDelay, true); + return AnimationReturnType(false, 10, true); +} + +// -------------------------------- +// Speech Animation +// -------------------------------- +// only draw yellow pause-dots +AnimationReturnType Animation_Speech(const bool startNewAnimation, CRGBSet &leds) { + (void) startNewAnimation; // start is not used + + leds = CRGB::Black; + uint8_t pauseOffset = 0; + if (OFFSET_PAUSE_LEDS) { + pauseOffset = ((leds.size() / NUM_LEDS_IDLE_DOTS) / 2) - 1; } + Led_DrawIdleDots(leds, pauseOffset, CRGB::Yellow); - // -------------------------------- - // Volume-Change Animation - // -------------------------------- - // - Single-LED: led indicates loudness between green (low) => red (high) - // - Multiple-LEDs: number of LEDs indicate loudness; gradient is shown between - // green (low) => red (high) - AnimationReturnType Animation_Volume(const bool startNewAnimation, CRGBSet &leds) { - // return-values - int32_t animationDelay = 0; - bool animationActive = true; - // static values - static uint16_t cyclesWaited = 0; - - // wait for further volume changes within next 20ms for 50 cycles = 1s - const uint32_t ledValue = std::clamp(map(AudioPlayer_GetCurrentVolume(), 0, AudioPlayer_GetMaxVolume(), 0, leds.size() * DIMMABLE_STATES), 0, leds.size() * DIMMABLE_STATES); - const uint8_t fullLeds = ledValue / DIMMABLE_STATES; - const uint8_t lastLed = ledValue % DIMMABLE_STATES; + return AnimationReturnType(false, 10, true); +} +// -------------------------------- +// Progress in Track Animation +// -------------------------------- +AnimationReturnType Animation_Progress(const bool startNewAnimation, CRGBSet &leds) { + // return values + int32_t animationDelay = 0; + // static values + static double lastPos = 0.0f; + + if (gPlayProperties.currentRelPos != lastPos || startNewAnimation) { + lastPos = gPlayProperties.currentRelPos; leds = CRGB::Black; - - if constexpr(NUM_INDICATOR_LEDS == 1) { - const uint8_t hue = 85 - (90 * - ((double)AudioPlayer_GetCurrentVolume() / - (double)AudioPlayer_GetMaxVolumeSpeaker())); - leds[0].setHue(hue); + if constexpr (NUM_INDICATOR_LEDS == 1) { + leds[0].setHue((uint8_t) (85 - ((double) 90 / 100) * gPlayProperties.currentRelPos)); } else { - /* - * (Inverse) color-gradient from green (85) back to (still) - * red (250) using unsigned-cast. - */ - for (int led = 0; led < fullLeds; led++) { - const uint8_t hue = (-86.0f) / (leds.size()-1) * led + 85.0f; - leds[Led_Address(led)].setHue(hue); + const uint32_t ledValue = std::clamp(map(gPlayProperties.currentRelPos, 0, 98, 0, leds.size() * DIMMABLE_STATES), 0, leds.size() * DIMMABLE_STATES); + const uint8_t fullLeds = ledValue / DIMMABLE_STATES; + const uint8_t lastLed = ledValue % DIMMABLE_STATES; + for (uint8_t led = 0; led < fullLeds; led++) { + if (System_AreControlsLocked()) { + leds[Led_Address(led)] = CRGB::Red; + } else if (!gPlayProperties.pausePlay) { // Hue-rainbow + leds[Led_Address(led)].setHue((uint8_t) (((float) PROGRESS_HUE_END - (float) PROGRESS_HUE_START) / (leds.size() - 1) * led + PROGRESS_HUE_START)); + } } if (lastLed > 0) { - const uint8_t hue = (-86.0f) / (leds.size()-1) * fullLeds + 85.0f; - leds[Led_Address(fullLeds)].setHue(hue); + if (System_AreControlsLocked()) { + leds[Led_Address(fullLeds)] = CRGB::Red; + } else { + leds[Led_Address(fullLeds)].setHue((uint8_t) (((float) PROGRESS_HUE_END - (float) PROGRESS_HUE_START) / (leds.size() - 1) * fullLeds + PROGRESS_HUE_START)); + } leds[Led_Address(fullLeds)] = Led_DimColor(leds[Led_Address(fullLeds)], lastLed); } } + animationDelay = 10; + } + return AnimationReturnType(false, animationDelay, true); +} - // reset animation if volume changes - if (LED_INDICATOR_IS_SET(LedIndicatorType::VolumeChange) || startNewAnimation) { - LED_INDICATOR_CLEAR(LedIndicatorType::VolumeChange); - cyclesWaited = 0; +// -------------------------------- +// Volume-Change Animation +// -------------------------------- +// - Single-LED: led indicates loudness between green (low) => red (high) +// - Multiple-LEDs: number of LEDs indicate loudness; gradient is shown between +// green (low) => red (high) +AnimationReturnType Animation_Volume(const bool startNewAnimation, CRGBSet &leds) { + // return-values + int32_t animationDelay = 0; + bool animationActive = true; + // static values + static uint16_t cyclesWaited = 0; + + // wait for further volume changes within next 20ms for 50 cycles = 1s + const uint32_t ledValue = std::clamp(map(AudioPlayer_GetCurrentVolume(), 0, AudioPlayer_GetMaxVolume(), 0, leds.size() * DIMMABLE_STATES), 0, leds.size() * DIMMABLE_STATES); + const uint8_t fullLeds = ledValue / DIMMABLE_STATES; + const uint8_t lastLed = ledValue % DIMMABLE_STATES; + + leds = CRGB::Black; + + if constexpr (NUM_INDICATOR_LEDS == 1) { + const uint8_t hue = 85 - (90 * ((double) AudioPlayer_GetCurrentVolume() / (double) AudioPlayer_GetMaxVolumeSpeaker())); + leds[0].setHue(hue); + } else { + /* + * (Inverse) color-gradient from green (85) back to (still) + * red (250) using unsigned-cast. + */ + for (int led = 0; led < fullLeds; led++) { + const uint8_t hue = (-86.0f) / (leds.size() - 1) * led + 85.0f; + leds[Led_Address(led)].setHue(hue); } - - if (cyclesWaited < LED_VOLUME_INDICATOR_NUM_CYCLES) { - animationDelay = 20; - cyclesWaited ++; - } else { - animationActive = false; - cyclesWaited = 0; + if (lastLed > 0) { + const uint8_t hue = (-86.0f) / (leds.size() - 1) * fullLeds + 85.0f; + leds[Led_Address(fullLeds)].setHue(hue); + leds[Led_Address(fullLeds)] = Led_DimColor(leds[Led_Address(fullLeds)], lastLed); } - return AnimationReturnType(animationActive, animationDelay, true); } - // -------------------------------- - // PLAYLIST-PROGRESS Animation - // -------------------------------- - AnimationReturnType Animation_PlaylistProgress(const bool startNewAnimation, CRGBSet &leds) { - // return-values - static bool animationActive = false; // signals if the animation is currently active - int32_t animationDelay = 0; - // static variables for animation - static LedPlaylistProgressStates animationState = LedPlaylistProgressStates::Done; // Statemachine-variable of this animation - static uint32_t animationCounter = 0; // counter-variable to loop through leds or to wait - static uint32_t staticLastBarLenghtPlaylist = 0; // variable to remember the last length of the progress-bar (for connecting animations) - static uint32_t staticLastTrack = 0; // variable to remember the last track (for connecting animations) - - if constexpr(NUM_INDICATOR_LEDS >= 4) { - if (gPlayProperties.numberOfTracks > 1 && gPlayProperties.currentTrackNumber < gPlayProperties.numberOfTracks) { - const uint32_t ledValue = std::clamp(map(gPlayProperties.currentTrackNumber, 0, gPlayProperties.numberOfTracks - 1, 0, leds.size() * DIMMABLE_STATES), 0, leds.size() * DIMMABLE_STATES); - const uint8_t fullLeds = ledValue / DIMMABLE_STATES; - const uint8_t lastLed = ledValue % DIMMABLE_STATES; - - if (LED_INDICATOR_IS_SET(LedIndicatorType::PlaylistProgress)) { - LED_INDICATOR_CLEAR(LedIndicatorType::PlaylistProgress); - // check if we need to animate a transition between from an already running animation - // only animate diff, if triggered again - if (!startNewAnimation) { - // forward progress - if (staticLastTrack < gPlayProperties.currentTrackNumber) { - if (animationState > LedPlaylistProgressStates::FillBar) { - animationState = LedPlaylistProgressStates::FillBar; - animationCounter = staticLastBarLenghtPlaylist; - } + // reset animation if volume changes + if (LED_INDICATOR_IS_SET(LedIndicatorType::VolumeChange) || startNewAnimation) { + LED_INDICATOR_CLEAR(LedIndicatorType::VolumeChange); + cyclesWaited = 0; + } + + if (cyclesWaited < LED_VOLUME_INDICATOR_NUM_CYCLES) { + animationDelay = 20; + cyclesWaited++; + } else { + animationActive = false; + cyclesWaited = 0; + } + return AnimationReturnType(animationActive, animationDelay, true); +} + +// -------------------------------- +// PLAYLIST-PROGRESS Animation +// -------------------------------- +AnimationReturnType Animation_PlaylistProgress(const bool startNewAnimation, CRGBSet &leds) { + // return-values + static bool animationActive = false; // signals if the animation is currently active + int32_t animationDelay = 0; + // static variables for animation + static LedPlaylistProgressStates animationState = LedPlaylistProgressStates::Done; // Statemachine-variable of this animation + static uint32_t animationCounter = 0; // counter-variable to loop through leds or to wait + static uint32_t staticLastBarLenghtPlaylist = 0; // variable to remember the last length of the progress-bar (for connecting animations) + static uint32_t staticLastTrack = 0; // variable to remember the last track (for connecting animations) + + if constexpr (NUM_INDICATOR_LEDS >= 4) { + if (gPlayProperties.numberOfTracks > 1 && gPlayProperties.currentTrackNumber < gPlayProperties.numberOfTracks) { + const uint32_t ledValue = std::clamp(map(gPlayProperties.currentTrackNumber, 0, gPlayProperties.numberOfTracks - 1, 0, leds.size() * DIMMABLE_STATES), 0, leds.size() * DIMMABLE_STATES); + const uint8_t fullLeds = ledValue / DIMMABLE_STATES; + const uint8_t lastLed = ledValue % DIMMABLE_STATES; + + if (LED_INDICATOR_IS_SET(LedIndicatorType::PlaylistProgress)) { + LED_INDICATOR_CLEAR(LedIndicatorType::PlaylistProgress); + // check if we need to animate a transition between from an already running animation + // only animate diff, if triggered again + if (!startNewAnimation) { + // forward progress + if (staticLastTrack < gPlayProperties.currentTrackNumber) { + if (animationState > LedPlaylistProgressStates::FillBar) { + animationState = LedPlaylistProgressStates::FillBar; + animationCounter = staticLastBarLenghtPlaylist; + } // backwards progress - } else if (staticLastTrack > gPlayProperties.currentTrackNumber) { - if (staticLastBarLenghtPlaylist < fullLeds) { - animationState = LedPlaylistProgressStates::FillBar; - animationCounter = staticLastBarLenghtPlaylist; - } else { - animationState = LedPlaylistProgressStates::EmptyBarToTarget; - animationCounter = staticLastBarLenghtPlaylist; - } + } else if (staticLastTrack > gPlayProperties.currentTrackNumber) { + if (staticLastBarLenghtPlaylist < fullLeds) { + animationState = LedPlaylistProgressStates::FillBar; + animationCounter = staticLastBarLenghtPlaylist; + } else { + animationState = LedPlaylistProgressStates::EmptyBarToTarget; + animationCounter = staticLastBarLenghtPlaylist; } } - staticLastTrack = gPlayProperties.currentTrackNumber; } + staticLastTrack = gPlayProperties.currentTrackNumber; + } - if (startNewAnimation) { - animationActive = true; - animationCounter = 0; - animationState = LedPlaylistProgressStates::FillBar; - } + if (startNewAnimation) { + animationActive = true; + animationCounter = 0; + animationState = LedPlaylistProgressStates::FillBar; + } - animationDelay = 30; - uint8_t barLength = 0; - switch (animationState) { - case LedPlaylistProgressStates::FillBar: - barLength = animationCounter; - if (animationCounter >= fullLeds) { - animationState = LedPlaylistProgressStates::Wait; - animationCounter = 0; - } else { - animationCounter++; - } + animationDelay = 30; + uint8_t barLength = 0; + switch (animationState) { + case LedPlaylistProgressStates::FillBar: + barLength = animationCounter; + if (animationCounter >= fullLeds) { + animationState = LedPlaylistProgressStates::Wait; + animationCounter = 0; + } else { + animationCounter++; + } break; - case LedPlaylistProgressStates::Wait: - // wait - animationCounter ++; - if (animationCounter >= 50) { - animationState = LedPlaylistProgressStates::EmptyBar; - animationCounter = fullLeds; - } - barLength = fullLeds; + case LedPlaylistProgressStates::Wait: + // wait + animationCounter++; + if (animationCounter >= 50) { + animationState = LedPlaylistProgressStates::EmptyBar; + animationCounter = fullLeds; + } + barLength = fullLeds; break; - case LedPlaylistProgressStates::EmptyBar: - // negative - barLength = animationCounter; - if (animationCounter == 0) { - animationState = LedPlaylistProgressStates::Done; - } else { - animationCounter--; - } + case LedPlaylistProgressStates::EmptyBar: + // negative + barLength = animationCounter; + if (animationCounter == 0) { + animationState = LedPlaylistProgressStates::Done; + } else { + animationCounter--; + } break; - case LedPlaylistProgressStates::EmptyBarToTarget: - // move back to target and wait there - barLength = animationCounter; - if (animationCounter <= fullLeds) { - animationState = LedPlaylistProgressStates::Wait; - animationCounter = 0; - } else { - animationCounter--; - } + case LedPlaylistProgressStates::EmptyBarToTarget: + // move back to target and wait there + barLength = animationCounter; + if (animationCounter <= fullLeds) { + animationState = LedPlaylistProgressStates::Wait; + animationCounter = 0; + } else { + animationCounter--; + } break; - default: - // done - animationActive = false; + default: + // done + animationActive = false; break; - } + } - // draw bar - leds = CRGB::Black; - for (uint8_t i = 0; i < barLength; i++) { - leds[Led_Address(i)] = CRGB::Blue; - } - if (barLength == fullLeds && lastLed > 0) { - leds[Led_Address(barLength)] = Led_DimColor(CRGB::Blue, lastLed); - } - staticLastBarLenghtPlaylist = barLength; + // draw bar + leds = CRGB::Black; + for (uint8_t i = 0; i < barLength; i++) { + leds[Led_Address(i)] = CRGB::Blue; } - } else { - // nothing to show. Just clear indicator - LED_INDICATOR_CLEAR(LedIndicatorType::PlaylistProgress); + if (barLength == fullLeds && lastLed > 0) { + leds[Led_Address(barLength)] = Led_DimColor(CRGB::Blue, lastLed); + } + staticLastBarLenghtPlaylist = barLength; } - - return AnimationReturnType(animationActive, animationDelay, true); + } else { + // nothing to show. Just clear indicator + LED_INDICATOR_CLEAR(LedIndicatorType::PlaylistProgress); } - // -------------------------------- - // BATTERY_MEASUREMENT Animation - // -------------------------------- - // Single-LED: indicates voltage coloured between gradient green (high) => red (low) - // Multi-LED: number of LEDs indicates voltage-level with having green >= 60% ; orange < 60% + >= 30% ; red < 30% - AnimationReturnType Animation_BatteryMeasurement(const bool startNewAnimation, CRGBSet &leds) { - // return-values - static bool animationActive = false; - bool refresh = false; - int32_t animationDelay = 0; - // static variables for animation - static float staticBatteryLevel = 0.0f; // variable to store the measured battery-voltage - static uint32_t filledLedCount = 0; // loop variable to animate led-bar - - LED_INDICATOR_CLEAR(LedIndicatorType::Voltage); - - if (startNewAnimation) { - #ifdef MEASURE_BATTERY_VOLTAGE - float batteryLevel = Battery_EstimateLevel(); - #else - float batteryLevel = 1.0f; - #endif - if (batteryLevel < 0.0f) { // If voltage is too low or no battery is connected - LED_INDICATOR_SET(LedIndicatorType::Error); - return AnimationReturnType(); // abort to indicate error - } - staticBatteryLevel = batteryLevel; - filledLedCount = 0; - animationActive = true; - leds = CRGB::Black; - refresh = true; + return AnimationReturnType(animationActive, animationDelay, true); +} + +// -------------------------------- +// BATTERY_MEASUREMENT Animation +// -------------------------------- +// Single-LED: indicates voltage coloured between gradient green (high) => red (low) +// Multi-LED: number of LEDs indicates voltage-level with having green >= 60% ; orange < 60% + >= 30% ; red < 30% +AnimationReturnType Animation_BatteryMeasurement(const bool startNewAnimation, CRGBSet &leds) { + // return-values + static bool animationActive = false; + bool refresh = false; + int32_t animationDelay = 0; + // static variables for animation + static float staticBatteryLevel = 0.0f; // variable to store the measured battery-voltage + static uint32_t filledLedCount = 0; // loop variable to animate led-bar + + LED_INDICATOR_CLEAR(LedIndicatorType::Voltage); + + if (startNewAnimation) { + #ifdef MEASURE_BATTERY_VOLTAGE + float batteryLevel = Battery_EstimateLevel(); + #else + float batteryLevel = 1.0f; + #endif + if (batteryLevel < 0.0f) { // If voltage is too low or no battery is connected + LED_INDICATOR_SET(LedIndicatorType::Error); + return AnimationReturnType(); // abort to indicate error + } + staticBatteryLevel = batteryLevel; + filledLedCount = 0; + animationActive = true; + leds = CRGB::Black; + refresh = true; + } + if constexpr (NUM_INDICATOR_LEDS == 1) { + if (staticBatteryLevel < 0.3) { + leds[0] = CRGB::Red; + } else if (staticBatteryLevel < 0.6) { + leds[0] = CRGB::Orange; + } else { + leds[0] = CRGB::Green; } - if constexpr(NUM_INDICATOR_LEDS == 1) { + refresh = true; + + animationDelay = 20 * 100; + animationActive = false; + } else { + uint8_t numLedsToLight = std::clamp(staticBatteryLevel * leds.size(), 0, leds.size()); + + // fill all needed LEDs + if (filledLedCount < numLedsToLight) { if (staticBatteryLevel < 0.3) { - leds[0] = CRGB::Red; + leds[Led_Address(filledLedCount)] = CRGB::Red; } else if (staticBatteryLevel < 0.6) { - leds[0] = CRGB::Orange; + leds[Led_Address(filledLedCount)] = CRGB::Orange; } else { - leds[0] = CRGB::Green; + leds[Led_Address(filledLedCount)] = CRGB::Green; } refresh = true; - animationDelay = 20*100; + filledLedCount++; + animationDelay = 20; + } else { // Wait a little + animationDelay = 20 * 100; animationActive = false; - } else { - uint8_t numLedsToLight = std::clamp(staticBatteryLevel * leds.size(), 0, leds.size()); - - // fill all needed LEDs - if (filledLedCount < numLedsToLight) { - if (staticBatteryLevel < 0.3) { - leds[Led_Address(filledLedCount)] = CRGB::Red; - } else if (staticBatteryLevel < 0.6) { - leds[Led_Address(filledLedCount)] = CRGB::Orange; - } else { - leds[Led_Address(filledLedCount)] = CRGB::Green; - } - refresh = true; - - filledLedCount ++; - animationDelay = 20; - } else { // Wait a little - animationDelay = 20*100; - animationActive = false; - } } - return AnimationReturnType(animationActive, animationDelay, refresh); } + return AnimationReturnType(animationActive, animationDelay, refresh); +} #endif void Led_TaskPause(void) { - #ifdef NEOPIXEL_ENABLE - vTaskSuspend(Led_TaskHandle); - FastLED.clear(true); - #endif +#ifdef NEOPIXEL_ENABLE + vTaskSuspend(Led_TaskHandle); + FastLED.clear(true); +#endif } void Led_TaskResume(void) { - #ifdef NEOPIXEL_ENABLE - vTaskResume(Led_TaskHandle); - #endif +#ifdef NEOPIXEL_ENABLE + vTaskResume(Led_TaskHandle); +#endif } diff --git a/src/Led.h b/src/Led.h index 7ae59d95..e36ef20a 100644 --- a/src/Led.h +++ b/src/Led.h @@ -1,7 +1,6 @@ #pragma once -typedef enum class LedIndicator -{ +typedef enum class LedIndicator { BootComplete = 0, Error, Ok, @@ -12,10 +11,8 @@ typedef enum class LedIndicator VolumeChange } LedIndicatorType; - // ordered by priority -enum class LedAnimationType -{ +enum class LedAnimationType { Boot = 0, Shutdown, Error, @@ -34,8 +31,7 @@ enum class LedAnimationType NoNewAnimation }; -enum class LedPlaylistProgressStates -{ +enum class LedPlaylistProgressStates { FillBar = 0, Wait, EmptyBar, @@ -44,16 +40,22 @@ enum class LedPlaylistProgressStates }; struct AnimationReturnType { - bool animationActive; - int32_t animationDelay; + bool animationActive; + int32_t animationDelay; bool animationRefresh; - void clear(){ + void clear() { animationActive = false; animationDelay = 0; } - AnimationReturnType() : animationActive(false), animationDelay(0), animationRefresh(false) {} - AnimationReturnType(bool active, int32_t delay, bool refresh = false) :animationActive(active), animationDelay(delay), animationRefresh(refresh) {} + AnimationReturnType() + : animationActive(false) + , animationDelay(0) + , animationRefresh(false) { } + AnimationReturnType(bool active, int32_t delay, bool refresh = false) + : animationActive(active) + , animationDelay(delay) + , animationRefresh(refresh) { } }; void Led_Init(void); diff --git a/src/Log.cpp b/src/Log.cpp index e3925838..ee231466 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -1,12 +1,14 @@ #include #include "settings.h" + #include "Log.h" -#include "MemX.h" + #include "LogRingBuffer.h" +#include "MemX.h" static LogRingBuffer *Log_RingBuffer = NULL; -void Log_Init(void){ +void Log_Init(void) { Serial.begin(115200); Log_RingBuffer = new LogRingBuffer(); } @@ -14,15 +16,15 @@ void Log_Init(void){ String getLoglevel(const uint8_t logLevel) { switch (logLevel) { case LOGLEVEL_ERROR: - return "E"; + return "E"; case LOGLEVEL_NOTICE: - return "N"; + return "N"; case LOGLEVEL_INFO: - return "I"; + return "I"; case LOGLEVEL_DEBUG: - return "D"; + return "D"; default: - return " "; + return " "; } } @@ -59,7 +61,7 @@ void Log_Print(const char *_logBuffer, const uint8_t _minLogLevel, bool printTim } int Log_Printf(const uint8_t _minLogLevel, const char *format, ...) { - char loc_buf[201]; // Allow a maximum buffer of 200 characters in a single log message + char loc_buf[201]; // Allow a maximum buffer of 200 characters in a single log message int len; va_list arg; @@ -77,7 +79,7 @@ int Log_Printf(const uint8_t _minLogLevel, const char *format, ...) { va_end(arg); - return std::min(len, sizeof(loc_buf)-1); + return std::min(len, sizeof(loc_buf) - 1); } String Log_GetRingBuffer(void) { diff --git a/src/Log.h b/src/Log.h index ea8ec1f9..fab09937 100644 --- a/src/Log.h +++ b/src/Log.h @@ -2,10 +2,10 @@ #include "logmessages.h" // Loglevels available (don't change!) -#define LOGLEVEL_ERROR 1 // only errors +#define LOGLEVEL_ERROR 1 // only errors #define LOGLEVEL_NOTICE 2 // errors + important messages -#define LOGLEVEL_INFO 3 // infos + errors + important messages -#define LOGLEVEL_DEBUG 4 // almost everything +#define LOGLEVEL_INFO 3 // infos + errors + important messages +#define LOGLEVEL_DEBUG 4 // almost everything /* Wrapper-function for serial-logging (with newline) _logBuffer: char* to log diff --git a/src/LogMessages_DE.cpp b/src/LogMessages_DE.cpp index 61edd7ae..21582b56 100644 --- a/src/LogMessages_DE.cpp +++ b/src/LogMessages_DE.cpp @@ -4,247 +4,247 @@ #if (LANGUAGE == DE) #include "Log.h" - const char tryConnectMqttS[] = "Versuche Verbindung zu MQTT-Broker aufzubauen: %s"; - const char mqttOk[] = "MQTT-Session aufgebaut."; - const char sleepTimerEOP[] = "Sleep-Timer: Nach dem letzten Track der Playlist."; - const char sleepTimerEOT[] = "Sleep-Timer: Nach dem Ende des laufenden Tracks."; - const char sleepTimerStop[] = "Sleep-Timer wurde deaktiviert."; - const char sleepTimerEO5[] = "Sleep Timer: Nach Ende des Titels oder, wenn früher, Ende der Playlist"; - const char sleepTimerAlreadyStopped[] = "Sleep-Timer ist bereits deaktiviert."; - const char sleepTimerSetTo[] = "Sleep-Timer gesetzt auf %u Minute(n)"; - const char allowButtons[] = "Alle Tasten werden freigegeben."; - const char lockButtons[] = "Alle Tasten werden gesperrt."; - const char noPlaylistNotAllowedMqtt[] = "Playmode kann nicht auf 'Keine Playlist' gesetzt werden via MQTT."; - const char playmodeChangedMQtt[] = "Playmode per MQTT angepasst."; - const char noPlaymodeChangeIfIdle[] = "Playmode kann nicht verändert werden, wenn keine Playlist aktiv ist."; - const char noValidTopic[] = "Kein gültiges Topic: %s"; - const char freePtr[] = "Ptr-Freigabe: %s (0x%04x)"; - const char freeMemory[] = "Freier Speicher: %u Bytes"; - const char writeEntryToNvs[] = "[%u] Schreibe Eintrag in NVS: %s => %s"; - const char freeMemoryAfterFree[] = "Freier Speicher nach Aufräumen: %u Bytes"; - const char releaseMemoryOfOldPlaylist[] = "Gebe Speicher der alten Playlist frei (Freier Speicher: %u Bytes)"; - const char dirOrFileDoesNotExist[] = "Datei oder Verzeichnis existiert nicht: %s"; - const char unableToAllocateMemForPlaylist[] = "Speicher für Playlist konnte nicht allokiert werden!"; - const char unableToAllocateMem[] = "Speicher konnte nicht allokiert werden!"; - const char fileModeDetected[] = "Dateimodus erkannt."; - const char nameOfFileFound[] = "Gefundenes File: %s"; - const char reallocCalled[] = "Speicher reallokiert."; - const char unableToAllocateMemForLinearPlaylist[] = "Speicher für lineare Playlist konnte nicht allokiert werden!"; - const char numberOfValidFiles[] = "Anzahl gültiger Files/Webstreams: %u"; - const char newLoudnessReceivedQueue[] = "Neue Lautstärke empfangen via Queue: %u"; - const char newCntrlReceivedQueue[] = "Kontroll-Kommando empfangen via Queue: %u"; - const char newPlaylistReceived[] = "Neue Playlist mit %d Titel(n) empfangen"; - const char repeatTrackDueToPlaymode[] = "Wiederhole Titel aufgrund von Playmode."; - const char repeatPlaylistDueToPlaymode[] = "Wiederhole Playlist aufgrund von Playmode."; - const char cmndStop[] = "Kommando: Stop"; - const char cmndPause[] = "Kommando: Pause"; - const char cmndResumeFromPause[] = "Kommando: Fortsetzen"; - const char cmndNextTrack[] = "Kommando: Nächster Titel"; - const char cmndPrevTrack[] = "Kommando: Vorheriger Titel"; - const char cmndFirstTrack[] = "Kommando: Erster Titel von Playlist"; - const char cmndLastTrack[] = "Kommando: Letzter Titel von Playlist"; - const char cmndDoesNotExist[] = "Dieses Kommando existiert nicht."; - const char lastTrackAlreadyActive[] = "Es wird bereits der letzte Track gespielt."; - const char trackStartAudiobook[] = "Titel wird im Hörspielmodus von vorne gespielt."; - const char trackStart[] = "Titel wird von vorne gespielt."; - const char trackChangeWebstream[] = "Im Webradio-Modus kann nicht an den Anfang gesprungen werden."; - const char endOfPlaylistReached[] = "Ende der Playlist erreicht."; - const char trackStartatPos[] = "Titel wird abgespielt ab Position %u"; - const char waitingForTaskQueues[] = "Task Queue für RFID existiert noch nicht, warte..."; - const char rfidScannerReady[] = "RFID-Tags koennen jetzt gescannt werden..."; - const char rfidTagDetected[] = "RFID-Karte erkannt: %s"; - const char rfid15693TagDetected[] = "RFID-Karte (ISO-15693) erkannt: "; - const char rfidTagReceived[] = "RFID-Karte empfangen"; - const char dontAccepctSameRfid[] = "Aktuelle RFID-Karte erneut aufgelegt - abgelehnt! (%s)"; - const char rfidTagUnknownInNvs[] = "RFID-Karte ist im NVS nicht hinterlegt."; - const char goToSleepDueToIdle[] = "Gehe in Deep Sleep wegen Inaktivität..."; - const char goToSleepDueToTimer[] = "Gehe in Deep Sleep wegen Sleep Timer..."; - const char goToSleepNow[] = "Gehe jetzt in Deep Sleep!"; - const char maxLoudnessReached[] = "Maximale Lautstärke bereits erreicht!"; - const char minLoudnessReached[] = "Minimale Lautstärke bereits erreicht!"; - const char errorOccured[] = "Fehler aufgetreten!"; - const char noMp3FilesInDir[] = "Verzeichnis beinhaltet keine mp3-Files."; - const char modeSingleTrack[] = "Modus: Einzelner Track"; - const char modeSingleTrackLoop[] = "Modus: Einzelner Track in Endlosschleife"; - const char modeSingleTrackRandom[] = "Modus: Einzelner Track eines Ordners zufällig"; - const char modeSingleAudiobook[] = "Modus: Hoerspiel"; - const char modeSingleAudiobookLoop[] = "Modus: Hoerspiel in Endlosschleife"; - const char modeAllTrackAlphSorted[] = "Modus: Spiele alle Tracks (alphabetisch sortiert) des Ordners '%s'"; - const char modeAllTrackRandom[] = "Modus: Spiele alle Tracks (zufällig sortiert) des Ordners '%s'"; - const char modeAllTrackAlphSortedLoop[] = "Modus: Alle Tracks eines Ordners sortiert (alphabetisch) in Endlosschleife"; - const char modeAllTrackRandomLoop[] = "Modus: Alle Tracks eines Ordners zufällig in Endlosschleife"; - const char modeWebstream[] = "Modus: Webstream"; - const char modeWebstreamM3u[] = "Modus: Webstream (lokale .m3u-Datei)"; - const char webstreamNotAvailable[] = "Aktuell kein Webstream möglich, da keine WLAN-Verbindung vorhanden!"; - const char modeInvalid[] = "Ungültiger Abspielmodus %d!"; - const char modeRepeatNone[] = "Repeatmodus: Kein Repeat"; - const char modeRepeatTrack[] = "Repeatmodus: Aktueller Titel"; - const char modeRepeatPlaylist[] = "Repeatmodus: Gesamte Playlist"; - const char modeRepeatTracknPlaylist[] = "Repeatmodus: Track und Playlist"; - const char modificatorAllButtonsLocked[] = "Modifikator: Alle Tasten werden per RFID gesperrt."; - const char modificatorAllButtonsUnlocked[] = "Modifikator: Alle Tasten werden per RFID freigegeben."; - const char modificatorSleepd[] = "Modifikator: Sleep-Timer wieder deaktiviert."; - const char modificatorSleepTimer15[] = "Modifikator: Sleep-Timer per RFID aktiviert (15 Minuten)."; - const char modificatorSleepTimer30[] = "Modifikator: Sleep-Timer per RFID aktiviert (30 Minuten)."; - const char modificatorSleepTimer60[] = "Modifikator: Sleep-Timer per RFID aktiviert (60 Minuten)."; - const char modificatorSleepTimer120[] = "Modifikator: Sleep-Timer per RFID aktiviert (2 Stunden)."; - const char ledsDimmedToNightmode[] = "LEDs wurden auf Nachtmodus gedimmt."; - const char ledsDimmedToInitialValue[] = "LEDs wurden auf initiale Helligkeit gedimmt."; - const char modificatorNotallowedWhenIdle[] = "Modifikator kann bei nicht aktivierter Playlist nicht angewendet werden."; - const char modificatorSleepAtEOT[] = "Modifikator: Sleep-Timer am Ende des Titels aktiviert."; - const char modificatorSleepAtEOTd[] = "Modifikator: Sleep-Timer am Ende des Titels deaktiviert."; - const char modificatorSleepAtEOP[] = "Modifikator: Sleep-Timer am Ende der Playlist aktiviert."; - const char modificatorSleepAtEOPd[] = "Modifikator: Sleep-Timer am Ende der Playlist deaktiviert."; - const char modificatorAllTrackAlphSortedLoop[] = "Modifikator: Alle Titel (alphabetisch sortiert) in Endlosschleife."; - const char modificatorAllTrackRandomLoop[] = "Modifikator: Alle Titel (zufällige Reihenfolge) in Endlosschleife."; - const char modificatorCurTrackLoop[] = "Modifikator: Aktueller Titel in Endlosschleife."; - const char modificatorCurAudiobookLoop[] = "Modifikator: Aktuelles Hörspiel in Endlosschleife."; - const char modificatorPlaylistLoopActive[] = "Modifikator: Alle Titel in Endlosschleife aktiviert."; - const char modificatorPlaylistLoopDeactive[] = "Modifikator: Alle Titel in Endlosschleife deaktiviert."; - const char modificatorTrackActive[] = "Modifikator: Titel in Endlosschleife aktiviert."; - const char modificatorTrackDeactive[] = "Modifikator: Titel in Endlosschleife deaktiviert."; - const char modificatorNotAllowed[] = "Modifikator konnte nicht angewendet werden."; - const char modificatorLoopRev[] = "Modifikator: Endlosschleife beendet."; - const char modificatorDoesNotExist[] = "Ein Karten-Modifikator existiert nicht vom Typ %d!"; - const char errorOccuredNvs[] = "Es ist ein Fehler aufgetreten beim Lesen aus dem NVS!"; - const char statementsReceivedByServer[] = "Vom Server wurde Folgendes empfangen"; - const char apReady[] = "Access-Point geöffnet"; - const char httpReady[] = "HTTP-Server gestartet."; - const char unableToMountSd[] = "SD-Karte konnte nicht gemountet werden."; - const char unableToCreateVolQ[] = "Konnte Volume-Queue nicht anlegen."; - const char unableToCreateRfidQ[] = "Konnte RFID-Queue nicht anlegen."; - const char unableToCreateMgmtQ[] = "Konnte Play-Management-Queue nicht anlegen."; - const char unableToCreatePlayQ[] = "Konnte Track-Queue nicht anlegen.."; - const char initialBrightnessfromNvs[] = "Initiale LED-Helligkeit wurde aus NVS geladen: %u"; - const char wroteInitialBrightnessToNvs[] = "Initiale LED-Helligkeit wurde ins NVS geschrieben."; - const char restoredInitialBrightnessForNmFromNvs[] = "LED-Helligkeit für Nachtmodus wurde aus NVS geladen: %u"; - const char wroteNmBrightnessToNvs[] = "LED-Helligkeit für Nachtmodus wurde ins NVS geschrieben."; - const char wroteFtpUserToNvs[] = "FTP-User wurde ins NVS geschrieben."; - const char restoredFtpUserFromNvs[] = "FTP-User wurde aus NVS geladen: %s"; - const char wroteFtpPwdToNvs[] = "FTP-Passwort wurde ins NVS geschrieben."; - const char restoredFtpPwdFromNvs[] = "FTP-Passwort wurde aus NVS geladen: %s"; - const char restoredMaxInactivityFromNvs[] = "Maximale Inaktivitätszeit wurde aus NVS geladen: %u Minuten"; - const char wroteMaxInactivityToNvs[] = "Maximale Inaktivitätszeit wurde ins NVS geschrieben."; - const char restoredInitialLoudnessFromNvs[] = "Initiale Lautstärke wurde aus NVS geladen: %u"; - const char wroteInitialLoudnessToNvs[] = "Initiale Lautstärke wurde ins NVS geschrieben."; - const char restoredMaxLoudnessForSpeakerFromNvs[] = "Maximale Lautstärke für Lautsprecher wurde aus NVS geladen: %u"; - const char restoredMaxLoudnessForHeadphoneFromNvs[] = "Maximale Lautstärke für Kopfhörer wurde aus NVS geladen: %u"; - const char wroteMaxLoudnessForSpeakerToNvs[] = "Maximale Lautstärke für Lautsprecher wurde ins NVS geschrieben."; - const char wroteMaxLoudnessForHeadphoneToNvs[] = "Maximale Lautstärke für Kopfhörer wurde ins NVS geschrieben."; - const char maxVolumeSet[] = "Maximale Lautstärke wurde gesetzt auf: %u"; - const char wroteMqttFlagToNvs[] = "MQTT-Flag wurde ins NVS geschrieben."; - const char restoredMqttActiveFromNvs[] = "MQTT-Flag (aktiviert) wurde aus NVS geladen: %u"; - const char restoredMqttDeactiveFromNvs[] = "MQTT-Flag (deaktiviert) wurde aus NVS geladen: %u"; - const char wroteMqttClientIdToNvs[] = "MQTT-ClientId wurde ins NVS geschrieben."; - const char restoredMqttClientIdFromNvs[] = "MQTT-ClientId wurde aus NVS geladen: %s"; - const char wroteMqttServerToNvs[] = "MQTT-Server wurde ins NVS geschrieben."; - const char restoredMqttServerFromNvs[] = "MQTT-Server wurde aus NVS geladen: %s"; - const char wroteMqttUserToNvs[] = "MQTT-User wurde ins NVS geschrieben."; - const char restoredMqttUserFromNvs[] = "MQTT-User wurde aus NVS geladen: %s"; - const char wroteMqttPwdToNvs[] = "MQTT-Passwort wurde ins NVS geschrieben."; - const char restoredMqttPwdFromNvs[] = "MQTT-Passwort wurde aus NVS geladen: %s"; - const char restoredMqttPortFromNvs[] = "MQTT-Port wurde aus NVS geladen: %u"; - const char mqttWithPwd[] = "Verbinde zu MQTT-Server mit User und Passwort"; - const char mqttWithoutPwd[] = "Verbinde zu MQTT-Server ohne User und Passwort"; - const char ssidNotFoundInNvs[] = "SSID wurde im NVS nicht gefunden."; - const char wifiStaticIpConfigNotFoundInNvs[] = "Statische WLAN-IP-Konfiguration wurde im NVS nicht gefunden."; - const char wifiHostnameNotSet[] = "Keine Hostname-Konfiguration im NVS gefunden."; - const char mqttConnFailed[] = "Verbindung fehlgeschlagen, versuche in Kürze erneut: rc=%i (%d / %d)"; - const char restoredHostnameFromNvs[] = "Hostname aus NVS geladen: %s"; - const char currentVoltageMsg[] = "Aktuelle Batteriespannung: %.2f V"; - const char currentChargeMsg[] = "Aktuelle Batterieladung: %.2f %%"; - const char batteryCurrentMsg[] = "Stromverbrauch (Batterie): %.2f mA"; - const char batteryTempMsg[] = "Temperatur der Batterie: %.2f°C"; - const char batteryCyclesMsg[] = "Gesehene Batteriezyklen: %.2f"; - const char batteryLowMsg[] = "Batterieladung niedrig"; - const char batteryCriticalMsg[] = "Batterieladung kritisch. Gehe in Deepsleep..."; - const char sdBootFailedDeepsleep[] = "Bootgang wegen SD fehlgeschlagen. Gehe in Deepsleep..."; - const char wifiEnabledMsg[] = "WLAN wird aktiviert."; - const char wifiDisabledMsg[] = "WLAN wird deaktiviert."; - const char voltageIndicatorLowFromNVS[] = "Unterer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen: %.2fV"; - const char voltageIndicatorHighFromNVS[] = "Oberer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen: %.2fV"; - const char batteryCheckIntervalFromNVS[] = "Zyklus für Batteriemessung fuer Neopixel-Anzeige aus NVS geladen: %u Minuten"; - const char warningLowVoltageFromNVS[] = "Spannungslevel (Batterie) fuer Niedrig-Warnung via Neopixel aus NVS geladen: %.2fV"; - const char warningCriticalVoltageFromNVS[] = "Spannungslevel (Batterie) fuer Kritisch-Warnung via Neopixel aus NVS geladen: %.2fV"; - const char batteryLowFromNVS[] = "Batterieladestand fuer Niedrig-Warnung via Neopixel aus NVS geladen: %.2f %%"; - const char batteryCriticalFromNVS[] = "Batterieladestand fuer Kritisch-Warnung via Neopixel aus NVS geladen: %.2f %%"; - const char unableToRestoreLastRfidFromNVS[] = "Letzte RFID konnte nicht aus NVS geladen werden"; - const char restoredLastRfidFromNVS[] = "Letzte RFID wurde aus NVS geladen: %s"; - const char failedOpenFileForWrite[] = "Öffnen der Datei für den Schreibvorgang fehlgeschlagen"; - const char fileWritten[] = "Datei geschrieben: %s => %zu bytes in %lu ms (%lu kiB/s)"; - const char writeFailed[] = "Schreibvorgang fehlgeschlagen"; - const char writingFile[] = "Schreibe Datei: %s"; - const char failedToOpenFileForAppending[] = "Öffnen der Datei zum Schreiben der JSON-Datei fehlgeschlagen"; - const char listingDirectory[] = "Verzeichnisinhalt anzeigen"; - const char failedToOpenDirectory[] = "Öffnen des Verzeichnisses fehlgeschlagen"; - const char notADirectory[] = "Kein Verzeichnis"; - const char sdMountedMmc1BitMode[] = "Versuche SD-Karte im SD_MMC-Modus (1 Bit) zu mounten..."; - const char sdMountedSpiMode[] = "Versuche SD-Karte im SPI-Modus zu mounten..."; - const char restartWebsite[] = "

Der ESPuino wird neu gestartet...
Zur letzten Seite zurückkehren.

"; - const char shutdownWebsite[] = "Der ESPuino wird ausgeschaltet..."; - const char mqttMsgReceived[] = "MQTT-Nachricht empfangen: [Topic: %s] [Command: %s]"; - const char trackPausedAtPos[] = "Titel pausiert bei Position: %u (%u)"; - const char freeHeapWithoutFtp[] = "Freier Heap-Speicher vor FTP-Instanzierung: %u"; - const char freeHeapWithFtp[] = "Freier Heap-Speicher nach FTP-Instanzierung: %u"; - const char ftpServerStarted[] = "FTP-Server gestartet"; - const char freeHeapAfterSetup[] = "Freier Heap-Speicher nach Setup-Routine"; - const char tryStaticIpConfig[] = "Statische IP-Konfiguration wird durchgeführt..."; - const char staticIPConfigFailed[] = "Statische IP-Konfiguration fehlgeschlagen"; - const char wakeUpRfidNoIso14443[] = "ESP32 wurde vom Kartenleser aus dem Deepsleep aufgeweckt. Allerdings wurde keine ISO-14443-Karte gefunden. Gehe zurück in den Deepsleep..."; - const char lowPowerCardSuccess[] = "Kartenerkennung via 'low power' erfolgreich durchgeführt"; - const char rememberLastVolume[] = "Lautstärke vor dem letzten Shutdown wird wiederhergestellt. Dies überschreibt die Einstellung der initialen Lautstärke aus der GUI."; - const char unableToStartFtpServer[] = "Der FTP-Server konnte nicht gestartet werden. Entweder weil er ist bereits gestartet oder kein WLAN verfügbar ist."; - const char unableToTellIpAddress[] = "IP-Adresse kann nicht angesagt werden, da keine WLAN-Verbindung besteht."; - const char unableToTellTime[] = "Uhrzeit kann nicht angesagt werden, da keine WLAN-Verbindung besteht."; - const char newPlayModeStereo[] = "Neuer Modus: stereo"; - const char newPlayModeMono[] = "Neuer Modus: mono"; - const char portExpanderFound[] = "Port-expander gefunden"; - const char portExpanderNotFound[] = "Port-expander nicht gefunden"; - const char portExpanderInterruptEnabled[] = "Interrupt für Port-Expander aktiviert"; - const char playlistGen[] = "Playlist-Generierung"; - const char bootLoopDetected[] = "Bootschleife erkannt! Letzte RFID wird nicht aufgerufen."; - const char noBootLoopDetected[] = "Keine Bootschleife erkannt. Wunderbar :-)"; - const char importCountNokNvs[] = "Anzahl der ungültigen Import-Einträge: %u"; - const char errorReadingTmpfile[] = "Beim Lesen der temporären Importdatei ist ein Fehler aufgetreten!"; - const char errorWritingTmpfile[] = "Beim Schreiben der temporären Importdatei ist ein Fehler aufgetreten!"; - const char eraseRfidNvs[] = "NVS-RFID-Zuweisungen werden gelöscht..."; - const char fwStart[] = "Starte Firmware-update via OTA..."; - const char fwEnd[] = "Firmware-update beendet"; - const char otaNotSupported[] = "Firmware-update wird von diesem ESPuino nicht unterstuetzt!"; - const char otaNotSupportedWebsite[] = "

Firmware-update wird von diesem ESPuino nicht unterstuetzt!
Zur letzten Seite zurückkehren.

"; - const char noPlaylist[] = "Keine Playlist aktiv."; - const char rfidTagRemoved[] = "RFID-Karte wurde entfernt"; - const char rfidTagReapplied[] = "RFID-Karte erneut aufgelegt"; - const char ftpEnableTooLate[] = "FTP kann nur innerhalb der ersten 30s aktiviert werden. Kinderschutz :-)"; - const char syncingViaNtp[] = "Synchronisiere Uhrzeit via NTP..."; - const char ntpGotTime[] = "Datum/Uhrzeit empfangen von NTP-Server: %02d.%02d.%4d, %02d:%02d:%02d"; - const char ntpFailed[] = "NTP: Datum/Uhrzeit (noch) nicht verfügbar"; - const char sdInfo[] = "SD-Kartengröße / freier Speicherplatz: %llu MB / %llu MB"; - const char paOn[] = "Lautsprecher eingeschaltet"; - const char paOff[] = "Lautsprecher ausgeschaltet"; - const char hpOn[] = "Kopfhörer eingeschaltet"; - const char hpOff[] = "Kopfhörer ausgeschaltet"; - const char webTxCanceled[] = "Der Webtransfer wurde aufgrund von Inaktivität beendet."; - const char tryToPickRandomDir[] = "Versuche ein zufälliges Unterverzeichnis zu finden aus: %s"; - const char pickedRandomDir[] = "Zufällig ausgewähltes Unterverzeichnis: %s"; - const char wrongWakeUpGpio[] = "Der gewählte GPIO ist nicht vom Typ RTC und unterstützt daher das Aufwecken des ESP32 nicht! (GPIO: %u)"; - const char currentlyPlaying[] = "'%s' wird abgespielt (%d von %d)"; - const char secondsJumpForward[] = "%d Sekunden nach vorne gesprungen"; - const char secondsJumpBackward[] = "%d Sekunden zurück gesprungen"; - const char wroteLastTrackToNvs[] = "Schreibe '%s' in NVS für RFID-Card-ID %s mit Abspielmodus %d und letzter Track %u"; - const char wifiConnectionInProgress[] = "Versuche mit WLAN '%s' zu verbinden..."; - const char wifiConnectionSuccess[] = "Verbunden mit WLAN '%s' (Signalstärke: %d dBm, Kanal: %d, MAC-Adresse: %s)"; - const char wifiCurrentIp[] = "Aktuelle IP: %s"; - const char jsonErrorMsg[] = "deserializeJson() fehlgeschlagen: %s"; - const char wifiDeleteNetwork[] = "Lösche gespeichertes WLAN %s"; - const char wifiNetworkLoaded[] = "SSID %d von NVS geladen: %s"; - const char wifiTooManyNetworks[] = "Anzahl der WLAN-Netze in NVS ist %d, aber es sind maximal %d erlaubt."; - const char wifiAddTooManyNetworks[] = "Kein Platz, weiteres WLAN zu speichern!"; - const char wifiAddNetwork[] = "Füge WLAN hinzu: %s"; - const char wifiUpdateNetwork[] = "Ändere Passwort für WLAN %s"; - const char wifiScanResult[] = "WLAN '%s'gefunden (Signalstärke: %d dBm, Kanal: %d, MAC-Adresse: %s)"; - const char cantConnectToWifi[] = "WLAN-Verbindung fehlgeschlagen."; - const char wifiSetLastSSID[] = "Schreibe letzte erfolgreiche SSID in NVS für WLAN Schnellstart: %s"; - const char mDNSStarted[] = "mDNS gestartet: http://%s.local"; - const char mDNSFailed[] = "mDNS Start fehlgeschlagen, Hostname: %s"; +const char tryConnectMqttS[] = "Versuche Verbindung zu MQTT-Broker aufzubauen: %s"; +const char mqttOk[] = "MQTT-Session aufgebaut."; +const char sleepTimerEOP[] = "Sleep-Timer: Nach dem letzten Track der Playlist."; +const char sleepTimerEOT[] = "Sleep-Timer: Nach dem Ende des laufenden Tracks."; +const char sleepTimerStop[] = "Sleep-Timer wurde deaktiviert."; +const char sleepTimerEO5[] = "Sleep Timer: Nach Ende des Titels oder, wenn früher, Ende der Playlist"; +const char sleepTimerAlreadyStopped[] = "Sleep-Timer ist bereits deaktiviert."; +const char sleepTimerSetTo[] = "Sleep-Timer gesetzt auf %u Minute(n)"; +const char allowButtons[] = "Alle Tasten werden freigegeben."; +const char lockButtons[] = "Alle Tasten werden gesperrt."; +const char noPlaylistNotAllowedMqtt[] = "Playmode kann nicht auf 'Keine Playlist' gesetzt werden via MQTT."; +const char playmodeChangedMQtt[] = "Playmode per MQTT angepasst."; +const char noPlaymodeChangeIfIdle[] = "Playmode kann nicht verändert werden, wenn keine Playlist aktiv ist."; +const char noValidTopic[] = "Kein gültiges Topic: %s"; +const char freePtr[] = "Ptr-Freigabe: %s (0x%04x)"; +const char freeMemory[] = "Freier Speicher: %u Bytes"; +const char writeEntryToNvs[] = "[%u] Schreibe Eintrag in NVS: %s => %s"; +const char freeMemoryAfterFree[] = "Freier Speicher nach Aufräumen: %u Bytes"; +const char releaseMemoryOfOldPlaylist[] = "Gebe Speicher der alten Playlist frei (Freier Speicher: %u Bytes)"; +const char dirOrFileDoesNotExist[] = "Datei oder Verzeichnis existiert nicht: %s"; +const char unableToAllocateMemForPlaylist[] = "Speicher für Playlist konnte nicht allokiert werden!"; +const char unableToAllocateMem[] = "Speicher konnte nicht allokiert werden!"; +const char fileModeDetected[] = "Dateimodus erkannt."; +const char nameOfFileFound[] = "Gefundenes File: %s"; +const char reallocCalled[] = "Speicher reallokiert."; +const char unableToAllocateMemForLinearPlaylist[] = "Speicher für lineare Playlist konnte nicht allokiert werden!"; +const char numberOfValidFiles[] = "Anzahl gültiger Files/Webstreams: %u"; +const char newLoudnessReceivedQueue[] = "Neue Lautstärke empfangen via Queue: %u"; +const char newCntrlReceivedQueue[] = "Kontroll-Kommando empfangen via Queue: %u"; +const char newPlaylistReceived[] = "Neue Playlist mit %d Titel(n) empfangen"; +const char repeatTrackDueToPlaymode[] = "Wiederhole Titel aufgrund von Playmode."; +const char repeatPlaylistDueToPlaymode[] = "Wiederhole Playlist aufgrund von Playmode."; +const char cmndStop[] = "Kommando: Stop"; +const char cmndPause[] = "Kommando: Pause"; +const char cmndResumeFromPause[] = "Kommando: Fortsetzen"; +const char cmndNextTrack[] = "Kommando: Nächster Titel"; +const char cmndPrevTrack[] = "Kommando: Vorheriger Titel"; +const char cmndFirstTrack[] = "Kommando: Erster Titel von Playlist"; +const char cmndLastTrack[] = "Kommando: Letzter Titel von Playlist"; +const char cmndDoesNotExist[] = "Dieses Kommando existiert nicht."; +const char lastTrackAlreadyActive[] = "Es wird bereits der letzte Track gespielt."; +const char trackStartAudiobook[] = "Titel wird im Hörspielmodus von vorne gespielt."; +const char trackStart[] = "Titel wird von vorne gespielt."; +const char trackChangeWebstream[] = "Im Webradio-Modus kann nicht an den Anfang gesprungen werden."; +const char endOfPlaylistReached[] = "Ende der Playlist erreicht."; +const char trackStartatPos[] = "Titel wird abgespielt ab Position %u"; +const char waitingForTaskQueues[] = "Task Queue für RFID existiert noch nicht, warte..."; +const char rfidScannerReady[] = "RFID-Tags koennen jetzt gescannt werden..."; +const char rfidTagDetected[] = "RFID-Karte erkannt: %s"; +const char rfid15693TagDetected[] = "RFID-Karte (ISO-15693) erkannt: "; +const char rfidTagReceived[] = "RFID-Karte empfangen"; +const char dontAccepctSameRfid[] = "Aktuelle RFID-Karte erneut aufgelegt - abgelehnt! (%s)"; +const char rfidTagUnknownInNvs[] = "RFID-Karte ist im NVS nicht hinterlegt."; +const char goToSleepDueToIdle[] = "Gehe in Deep Sleep wegen Inaktivität..."; +const char goToSleepDueToTimer[] = "Gehe in Deep Sleep wegen Sleep Timer..."; +const char goToSleepNow[] = "Gehe jetzt in Deep Sleep!"; +const char maxLoudnessReached[] = "Maximale Lautstärke bereits erreicht!"; +const char minLoudnessReached[] = "Minimale Lautstärke bereits erreicht!"; +const char errorOccured[] = "Fehler aufgetreten!"; +const char noMp3FilesInDir[] = "Verzeichnis beinhaltet keine mp3-Files."; +const char modeSingleTrack[] = "Modus: Einzelner Track"; +const char modeSingleTrackLoop[] = "Modus: Einzelner Track in Endlosschleife"; +const char modeSingleTrackRandom[] = "Modus: Einzelner Track eines Ordners zufällig"; +const char modeSingleAudiobook[] = "Modus: Hoerspiel"; +const char modeSingleAudiobookLoop[] = "Modus: Hoerspiel in Endlosschleife"; +const char modeAllTrackAlphSorted[] = "Modus: Spiele alle Tracks (alphabetisch sortiert) des Ordners '%s'"; +const char modeAllTrackRandom[] = "Modus: Spiele alle Tracks (zufällig sortiert) des Ordners '%s'"; +const char modeAllTrackAlphSortedLoop[] = "Modus: Alle Tracks eines Ordners sortiert (alphabetisch) in Endlosschleife"; +const char modeAllTrackRandomLoop[] = "Modus: Alle Tracks eines Ordners zufällig in Endlosschleife"; +const char modeWebstream[] = "Modus: Webstream"; +const char modeWebstreamM3u[] = "Modus: Webstream (lokale .m3u-Datei)"; +const char webstreamNotAvailable[] = "Aktuell kein Webstream möglich, da keine WLAN-Verbindung vorhanden!"; +const char modeInvalid[] = "Ungültiger Abspielmodus %d!"; +const char modeRepeatNone[] = "Repeatmodus: Kein Repeat"; +const char modeRepeatTrack[] = "Repeatmodus: Aktueller Titel"; +const char modeRepeatPlaylist[] = "Repeatmodus: Gesamte Playlist"; +const char modeRepeatTracknPlaylist[] = "Repeatmodus: Track und Playlist"; +const char modificatorAllButtonsLocked[] = "Modifikator: Alle Tasten werden per RFID gesperrt."; +const char modificatorAllButtonsUnlocked[] = "Modifikator: Alle Tasten werden per RFID freigegeben."; +const char modificatorSleepd[] = "Modifikator: Sleep-Timer wieder deaktiviert."; +const char modificatorSleepTimer15[] = "Modifikator: Sleep-Timer per RFID aktiviert (15 Minuten)."; +const char modificatorSleepTimer30[] = "Modifikator: Sleep-Timer per RFID aktiviert (30 Minuten)."; +const char modificatorSleepTimer60[] = "Modifikator: Sleep-Timer per RFID aktiviert (60 Minuten)."; +const char modificatorSleepTimer120[] = "Modifikator: Sleep-Timer per RFID aktiviert (2 Stunden)."; +const char ledsDimmedToNightmode[] = "LEDs wurden auf Nachtmodus gedimmt."; +const char ledsDimmedToInitialValue[] = "LEDs wurden auf initiale Helligkeit gedimmt."; +const char modificatorNotallowedWhenIdle[] = "Modifikator kann bei nicht aktivierter Playlist nicht angewendet werden."; +const char modificatorSleepAtEOT[] = "Modifikator: Sleep-Timer am Ende des Titels aktiviert."; +const char modificatorSleepAtEOTd[] = "Modifikator: Sleep-Timer am Ende des Titels deaktiviert."; +const char modificatorSleepAtEOP[] = "Modifikator: Sleep-Timer am Ende der Playlist aktiviert."; +const char modificatorSleepAtEOPd[] = "Modifikator: Sleep-Timer am Ende der Playlist deaktiviert."; +const char modificatorAllTrackAlphSortedLoop[] = "Modifikator: Alle Titel (alphabetisch sortiert) in Endlosschleife."; +const char modificatorAllTrackRandomLoop[] = "Modifikator: Alle Titel (zufällige Reihenfolge) in Endlosschleife."; +const char modificatorCurTrackLoop[] = "Modifikator: Aktueller Titel in Endlosschleife."; +const char modificatorCurAudiobookLoop[] = "Modifikator: Aktuelles Hörspiel in Endlosschleife."; +const char modificatorPlaylistLoopActive[] = "Modifikator: Alle Titel in Endlosschleife aktiviert."; +const char modificatorPlaylistLoopDeactive[] = "Modifikator: Alle Titel in Endlosschleife deaktiviert."; +const char modificatorTrackActive[] = "Modifikator: Titel in Endlosschleife aktiviert."; +const char modificatorTrackDeactive[] = "Modifikator: Titel in Endlosschleife deaktiviert."; +const char modificatorNotAllowed[] = "Modifikator konnte nicht angewendet werden."; +const char modificatorLoopRev[] = "Modifikator: Endlosschleife beendet."; +const char modificatorDoesNotExist[] = "Ein Karten-Modifikator existiert nicht vom Typ %d!"; +const char errorOccuredNvs[] = "Es ist ein Fehler aufgetreten beim Lesen aus dem NVS!"; +const char statementsReceivedByServer[] = "Vom Server wurde Folgendes empfangen"; +const char apReady[] = "Access-Point geöffnet"; +const char httpReady[] = "HTTP-Server gestartet."; +const char unableToMountSd[] = "SD-Karte konnte nicht gemountet werden."; +const char unableToCreateVolQ[] = "Konnte Volume-Queue nicht anlegen."; +const char unableToCreateRfidQ[] = "Konnte RFID-Queue nicht anlegen."; +const char unableToCreateMgmtQ[] = "Konnte Play-Management-Queue nicht anlegen."; +const char unableToCreatePlayQ[] = "Konnte Track-Queue nicht anlegen.."; +const char initialBrightnessfromNvs[] = "Initiale LED-Helligkeit wurde aus NVS geladen: %u"; +const char wroteInitialBrightnessToNvs[] = "Initiale LED-Helligkeit wurde ins NVS geschrieben."; +const char restoredInitialBrightnessForNmFromNvs[] = "LED-Helligkeit für Nachtmodus wurde aus NVS geladen: %u"; +const char wroteNmBrightnessToNvs[] = "LED-Helligkeit für Nachtmodus wurde ins NVS geschrieben."; +const char wroteFtpUserToNvs[] = "FTP-User wurde ins NVS geschrieben."; +const char restoredFtpUserFromNvs[] = "FTP-User wurde aus NVS geladen: %s"; +const char wroteFtpPwdToNvs[] = "FTP-Passwort wurde ins NVS geschrieben."; +const char restoredFtpPwdFromNvs[] = "FTP-Passwort wurde aus NVS geladen: %s"; +const char restoredMaxInactivityFromNvs[] = "Maximale Inaktivitätszeit wurde aus NVS geladen: %u Minuten"; +const char wroteMaxInactivityToNvs[] = "Maximale Inaktivitätszeit wurde ins NVS geschrieben."; +const char restoredInitialLoudnessFromNvs[] = "Initiale Lautstärke wurde aus NVS geladen: %u"; +const char wroteInitialLoudnessToNvs[] = "Initiale Lautstärke wurde ins NVS geschrieben."; +const char restoredMaxLoudnessForSpeakerFromNvs[] = "Maximale Lautstärke für Lautsprecher wurde aus NVS geladen: %u"; +const char restoredMaxLoudnessForHeadphoneFromNvs[] = "Maximale Lautstärke für Kopfhörer wurde aus NVS geladen: %u"; +const char wroteMaxLoudnessForSpeakerToNvs[] = "Maximale Lautstärke für Lautsprecher wurde ins NVS geschrieben."; +const char wroteMaxLoudnessForHeadphoneToNvs[] = "Maximale Lautstärke für Kopfhörer wurde ins NVS geschrieben."; +const char maxVolumeSet[] = "Maximale Lautstärke wurde gesetzt auf: %u"; +const char wroteMqttFlagToNvs[] = "MQTT-Flag wurde ins NVS geschrieben."; +const char restoredMqttActiveFromNvs[] = "MQTT-Flag (aktiviert) wurde aus NVS geladen: %u"; +const char restoredMqttDeactiveFromNvs[] = "MQTT-Flag (deaktiviert) wurde aus NVS geladen: %u"; +const char wroteMqttClientIdToNvs[] = "MQTT-ClientId wurde ins NVS geschrieben."; +const char restoredMqttClientIdFromNvs[] = "MQTT-ClientId wurde aus NVS geladen: %s"; +const char wroteMqttServerToNvs[] = "MQTT-Server wurde ins NVS geschrieben."; +const char restoredMqttServerFromNvs[] = "MQTT-Server wurde aus NVS geladen: %s"; +const char wroteMqttUserToNvs[] = "MQTT-User wurde ins NVS geschrieben."; +const char restoredMqttUserFromNvs[] = "MQTT-User wurde aus NVS geladen: %s"; +const char wroteMqttPwdToNvs[] = "MQTT-Passwort wurde ins NVS geschrieben."; +const char restoredMqttPwdFromNvs[] = "MQTT-Passwort wurde aus NVS geladen: %s"; +const char restoredMqttPortFromNvs[] = "MQTT-Port wurde aus NVS geladen: %u"; +const char mqttWithPwd[] = "Verbinde zu MQTT-Server mit User und Passwort"; +const char mqttWithoutPwd[] = "Verbinde zu MQTT-Server ohne User und Passwort"; +const char ssidNotFoundInNvs[] = "SSID wurde im NVS nicht gefunden."; +const char wifiStaticIpConfigNotFoundInNvs[] = "Statische WLAN-IP-Konfiguration wurde im NVS nicht gefunden."; +const char wifiHostnameNotSet[] = "Keine Hostname-Konfiguration im NVS gefunden."; +const char mqttConnFailed[] = "Verbindung fehlgeschlagen, versuche in Kürze erneut: rc=%i (%d / %d)"; +const char restoredHostnameFromNvs[] = "Hostname aus NVS geladen: %s"; +const char currentVoltageMsg[] = "Aktuelle Batteriespannung: %.2f V"; +const char currentChargeMsg[] = "Aktuelle Batterieladung: %.2f %%"; +const char batteryCurrentMsg[] = "Stromverbrauch (Batterie): %.2f mA"; +const char batteryTempMsg[] = "Temperatur der Batterie: %.2f°C"; +const char batteryCyclesMsg[] = "Gesehene Batteriezyklen: %.2f"; +const char batteryLowMsg[] = "Batterieladung niedrig"; +const char batteryCriticalMsg[] = "Batterieladung kritisch. Gehe in Deepsleep..."; +const char sdBootFailedDeepsleep[] = "Bootgang wegen SD fehlgeschlagen. Gehe in Deepsleep..."; +const char wifiEnabledMsg[] = "WLAN wird aktiviert."; +const char wifiDisabledMsg[] = "WLAN wird deaktiviert."; +const char voltageIndicatorLowFromNVS[] = "Unterer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen: %.2fV"; +const char voltageIndicatorHighFromNVS[] = "Oberer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen: %.2fV"; +const char batteryCheckIntervalFromNVS[] = "Zyklus für Batteriemessung fuer Neopixel-Anzeige aus NVS geladen: %u Minuten"; +const char warningLowVoltageFromNVS[] = "Spannungslevel (Batterie) fuer Niedrig-Warnung via Neopixel aus NVS geladen: %.2fV"; +const char warningCriticalVoltageFromNVS[] = "Spannungslevel (Batterie) fuer Kritisch-Warnung via Neopixel aus NVS geladen: %.2fV"; +const char batteryLowFromNVS[] = "Batterieladestand fuer Niedrig-Warnung via Neopixel aus NVS geladen: %.2f %%"; +const char batteryCriticalFromNVS[] = "Batterieladestand fuer Kritisch-Warnung via Neopixel aus NVS geladen: %.2f %%"; +const char unableToRestoreLastRfidFromNVS[] = "Letzte RFID konnte nicht aus NVS geladen werden"; +const char restoredLastRfidFromNVS[] = "Letzte RFID wurde aus NVS geladen: %s"; +const char failedOpenFileForWrite[] = "Öffnen der Datei für den Schreibvorgang fehlgeschlagen"; +const char fileWritten[] = "Datei geschrieben: %s => %zu bytes in %lu ms (%lu kiB/s)"; +const char writeFailed[] = "Schreibvorgang fehlgeschlagen"; +const char writingFile[] = "Schreibe Datei: %s"; +const char failedToOpenFileForAppending[] = "Öffnen der Datei zum Schreiben der JSON-Datei fehlgeschlagen"; +const char listingDirectory[] = "Verzeichnisinhalt anzeigen"; +const char failedToOpenDirectory[] = "Öffnen des Verzeichnisses fehlgeschlagen"; +const char notADirectory[] = "Kein Verzeichnis"; +const char sdMountedMmc1BitMode[] = "Versuche SD-Karte im SD_MMC-Modus (1 Bit) zu mounten..."; +const char sdMountedSpiMode[] = "Versuche SD-Karte im SPI-Modus zu mounten..."; +const char restartWebsite[] = "

Der ESPuino wird neu gestartet...
Zur letzten Seite zurückkehren.

"; +const char shutdownWebsite[] = "Der ESPuino wird ausgeschaltet..."; +const char mqttMsgReceived[] = "MQTT-Nachricht empfangen: [Topic: %s] [Command: %s]"; +const char trackPausedAtPos[] = "Titel pausiert bei Position: %u (%u)"; +const char freeHeapWithoutFtp[] = "Freier Heap-Speicher vor FTP-Instanzierung: %u"; +const char freeHeapWithFtp[] = "Freier Heap-Speicher nach FTP-Instanzierung: %u"; +const char ftpServerStarted[] = "FTP-Server gestartet"; +const char freeHeapAfterSetup[] = "Freier Heap-Speicher nach Setup-Routine"; +const char tryStaticIpConfig[] = "Statische IP-Konfiguration wird durchgeführt..."; +const char staticIPConfigFailed[] = "Statische IP-Konfiguration fehlgeschlagen"; +const char wakeUpRfidNoIso14443[] = "ESP32 wurde vom Kartenleser aus dem Deepsleep aufgeweckt. Allerdings wurde keine ISO-14443-Karte gefunden. Gehe zurück in den Deepsleep..."; +const char lowPowerCardSuccess[] = "Kartenerkennung via 'low power' erfolgreich durchgeführt"; +const char rememberLastVolume[] = "Lautstärke vor dem letzten Shutdown wird wiederhergestellt. Dies überschreibt die Einstellung der initialen Lautstärke aus der GUI."; +const char unableToStartFtpServer[] = "Der FTP-Server konnte nicht gestartet werden. Entweder weil er ist bereits gestartet oder kein WLAN verfügbar ist."; +const char unableToTellIpAddress[] = "IP-Adresse kann nicht angesagt werden, da keine WLAN-Verbindung besteht."; +const char unableToTellTime[] = "Uhrzeit kann nicht angesagt werden, da keine WLAN-Verbindung besteht."; +const char newPlayModeStereo[] = "Neuer Modus: stereo"; +const char newPlayModeMono[] = "Neuer Modus: mono"; +const char portExpanderFound[] = "Port-expander gefunden"; +const char portExpanderNotFound[] = "Port-expander nicht gefunden"; +const char portExpanderInterruptEnabled[] = "Interrupt für Port-Expander aktiviert"; +const char playlistGen[] = "Playlist-Generierung"; +const char bootLoopDetected[] = "Bootschleife erkannt! Letzte RFID wird nicht aufgerufen."; +const char noBootLoopDetected[] = "Keine Bootschleife erkannt. Wunderbar :-)"; +const char importCountNokNvs[] = "Anzahl der ungültigen Import-Einträge: %u"; +const char errorReadingTmpfile[] = "Beim Lesen der temporären Importdatei ist ein Fehler aufgetreten!"; +const char errorWritingTmpfile[] = "Beim Schreiben der temporären Importdatei ist ein Fehler aufgetreten!"; +const char eraseRfidNvs[] = "NVS-RFID-Zuweisungen werden gelöscht..."; +const char fwStart[] = "Starte Firmware-update via OTA..."; +const char fwEnd[] = "Firmware-update beendet"; +const char otaNotSupported[] = "Firmware-update wird von diesem ESPuino nicht unterstuetzt!"; +const char otaNotSupportedWebsite[] = "

Firmware-update wird von diesem ESPuino nicht unterstuetzt!
Zur letzten Seite zurückkehren.

"; +const char noPlaylist[] = "Keine Playlist aktiv."; +const char rfidTagRemoved[] = "RFID-Karte wurde entfernt"; +const char rfidTagReapplied[] = "RFID-Karte erneut aufgelegt"; +const char ftpEnableTooLate[] = "FTP kann nur innerhalb der ersten 30s aktiviert werden. Kinderschutz :-)"; +const char syncingViaNtp[] = "Synchronisiere Uhrzeit via NTP..."; +const char ntpGotTime[] = "Datum/Uhrzeit empfangen von NTP-Server: %02d.%02d.%4d, %02d:%02d:%02d"; +const char ntpFailed[] = "NTP: Datum/Uhrzeit (noch) nicht verfügbar"; +const char sdInfo[] = "SD-Kartengröße / freier Speicherplatz: %llu MB / %llu MB"; +const char paOn[] = "Lautsprecher eingeschaltet"; +const char paOff[] = "Lautsprecher ausgeschaltet"; +const char hpOn[] = "Kopfhörer eingeschaltet"; +const char hpOff[] = "Kopfhörer ausgeschaltet"; +const char webTxCanceled[] = "Der Webtransfer wurde aufgrund von Inaktivität beendet."; +const char tryToPickRandomDir[] = "Versuche ein zufälliges Unterverzeichnis zu finden aus: %s"; +const char pickedRandomDir[] = "Zufällig ausgewähltes Unterverzeichnis: %s"; +const char wrongWakeUpGpio[] = "Der gewählte GPIO ist nicht vom Typ RTC und unterstützt daher das Aufwecken des ESP32 nicht! (GPIO: %u)"; +const char currentlyPlaying[] = "'%s' wird abgespielt (%d von %d)"; +const char secondsJumpForward[] = "%d Sekunden nach vorne gesprungen"; +const char secondsJumpBackward[] = "%d Sekunden zurück gesprungen"; +const char wroteLastTrackToNvs[] = "Schreibe '%s' in NVS für RFID-Card-ID %s mit Abspielmodus %d und letzter Track %u"; +const char wifiConnectionInProgress[] = "Versuche mit WLAN '%s' zu verbinden..."; +const char wifiConnectionSuccess[] = "Verbunden mit WLAN '%s' (Signalstärke: %d dBm, Kanal: %d, MAC-Adresse: %s)"; +const char wifiCurrentIp[] = "Aktuelle IP: %s"; +const char jsonErrorMsg[] = "deserializeJson() fehlgeschlagen: %s"; +const char wifiDeleteNetwork[] = "Lösche gespeichertes WLAN %s"; +const char wifiNetworkLoaded[] = "SSID %d von NVS geladen: %s"; +const char wifiTooManyNetworks[] = "Anzahl der WLAN-Netze in NVS ist %d, aber es sind maximal %d erlaubt."; +const char wifiAddTooManyNetworks[] = "Kein Platz, weiteres WLAN zu speichern!"; +const char wifiAddNetwork[] = "Füge WLAN hinzu: %s"; +const char wifiUpdateNetwork[] = "Ändere Passwort für WLAN %s"; +const char wifiScanResult[] = "WLAN '%s'gefunden (Signalstärke: %d dBm, Kanal: %d, MAC-Adresse: %s)"; +const char cantConnectToWifi[] = "WLAN-Verbindung fehlgeschlagen."; +const char wifiSetLastSSID[] = "Schreibe letzte erfolgreiche SSID in NVS für WLAN Schnellstart: %s"; +const char mDNSStarted[] = "mDNS gestartet: http://%s.local"; +const char mDNSFailed[] = "mDNS Start fehlgeschlagen, Hostname: %s"; #endif diff --git a/src/LogMessages_EN.cpp b/src/LogMessages_EN.cpp index cd7d3a64..c8db6dab 100644 --- a/src/LogMessages_EN.cpp +++ b/src/LogMessages_EN.cpp @@ -4,247 +4,247 @@ #if (LANGUAGE == EN) #include "Log.h" - const char tryConnectMqttS[] = "Trying to connect to MQTT-broker: %s"; - const char mqttOk[] = "MQTT-connection established."; - const char sleepTimerEOP[] = "Sleep-timer: after last track of playlist."; - const char sleepTimerEOT[] = "Sleep-timer: after end of current track."; - const char sleepTimerStop[] = "Sleep-timer has been disabled."; - const char sleepTimerEO5[] = "Sleep-timer: after five track or end of playlist - whatever is reached first"; - const char sleepTimerAlreadyStopped[] = "sleep-timer is already disabled."; - const char sleepTimerSetTo[] = "sleep-timer adjusted to %u minute(s)"; - const char allowButtons[] = "Unlocking all keys."; - const char lockButtons[] = "Locking all keys."; - const char noPlaylistNotAllowedMqtt[] = "Playmode cannot be adjusted to 'no playlist' via MQTT."; - const char playmodeChangedMQtt[] = "Playlist adjusted via MQTT."; - const char noPlaymodeChangeIfIdle[] = "Playlist cannot be adjusted while no playlist is active."; - const char noValidTopic[] = "No valid MQTT-topic: %s"; - const char freePtr[] = "Releasing Pointer: %s (0x%04x)"; - const char freeMemory[] = "Free memory: %u Bytes"; - const char writeEntryToNvs[] = "[%u] Storing data to NVS: %s => %s"; - const char freeMemoryAfterFree[] = "Free memory after cleaning: %u Bytes"; - const char releaseMemoryOfOldPlaylist[] = "Releasing memory of old playlist (Free memory: %u Bytes)."; - const char dirOrFileDoesNotExist[] = "File of directory does not exist: %s"; - const char unableToAllocateMemForPlaylist[] = "Unable to allocate memory for playlist!"; - const char unableToAllocateMem[] = "Unable to allocate memory!"; - const char fileModeDetected[] = "File-mode detected."; - const char nameOfFileFound[] = "File found: %s"; - const char reallocCalled[] = "Reallocated memory."; - const char unableToAllocateMemForLinearPlaylist[] = "Unable to allocate memory for linear playlist!"; - const char numberOfValidFiles[] = "Number of valid files/webstreams: %u"; - const char newLoudnessReceivedQueue[] = "New volume received via queue: %u"; - const char newCntrlReceivedQueue[] = "Control-command received via queue: %u"; - const char newPlaylistReceived[] = "New playlist received with %d track(s)"; - const char repeatTrackDueToPlaymode[] = "Repeating track due to playmode configured."; - const char repeatPlaylistDueToPlaymode[] = "Repeating playlist due to playmode configured."; - const char cmndStop[] = "Command: stop"; - const char cmndPause[] = "Command: pause"; - const char cmndResumeFromPause[] = "Command: resume"; - const char cmndNextTrack[] = "Command: next track"; - const char cmndPrevTrack[] = "Command: previous track"; - const char cmndFirstTrack[] = "Command: first track of playlist"; - const char cmndLastTrack[] = "Command: last track of playlist"; - const char cmndDoesNotExist[] = "Command requested does not exist."; - const char lastTrackAlreadyActive[] = "Already playing last track."; - const char trackStartAudiobook[] = "Starting track in playmode from the very beginning."; - const char trackStart[] = "Starting track from the very beginning."; - const char trackChangeWebstream[] = "Playing from the very beginning is not possible while webradio-mode is active."; - const char endOfPlaylistReached[] = "Reached end of playlist."; - const char trackStartatPos[] = "Starting track at position %u"; - const char waitingForTaskQueues[] = "Task Queue for RFID does not exist yet, waiting..."; - const char rfidScannerReady[] = "RFID-tags can now be applied..."; - const char rfidTagDetected[] = "RFID-tag detected: %s"; - const char rfid15693TagDetected[] = "RFID-ta (ISO-15693) detected: "; - const char rfidTagReceived[] = "RFID-tag received"; - const char dontAccepctSameRfid[] = "Reapplied same rfid-tag - rejected! (%s)"; - const char rfidTagUnknownInNvs[] = "RFID-tag is unkown to NVS."; - const char goToSleepDueToIdle[] = "Going to deepsleep due to inactivity-timer..."; - const char goToSleepDueToTimer[] = "Going to deepsleep due to sleep timer..."; - const char goToSleepNow[] = "Going to deepsleep now!"; - const char maxLoudnessReached[] = "Already reached max volume!"; - const char minLoudnessReached[] = "Already reached min volume!"; - const char errorOccured[] = "Error occured!"; - const char noMp3FilesInDir[] = "Directory does not contain mp3-files."; - const char modeSingleTrack[] = "Mode: Single track"; - const char modeSingleTrackLoop[] = "Mode: single track as infinite loop"; - const char modeSingleTrackRandom[] = "Mode: single track (random) of directory"; - const char modeSingleAudiobook[] = "Mode: audiobook"; - const char modeSingleAudiobookLoop[] = "Mode: audiobook as infinite loop"; - const char modeAllTrackAlphSorted[] = "Mode: all tracks (in alph. order) of directory '%s'"; - const char modeAllTrackRandom[] = "Mode: all tracks (in random. order) of directory '%s"; - const char modeAllTrackAlphSortedLoop[] = "Mode: all tracks (in alph. order) of directory as infinite loop"; - const char modeAllTrackRandomLoop[] = "Mode: all tracks (in random order) of directory as infinite loop"; - const char modeWebstream[] = "Mode: webstream"; - const char modeWebstreamM3u[] = "Mode: Webstream (local .m3u-file)"; - const char webstreamNotAvailable[] = "Unable to access webstream as no wifi-connection is available!"; - const char modeDoesNotExist[] = "Playmode does not exist!"; - const char modeRepeatNone[] = "Repeatmode: no repeat"; - const char modeRepeatTrack[] = "Repeatmode: current track"; - const char modeRepeatPlaylist[] = "Repeatmode: whole playlist"; - const char modeRepeatTracknPlaylist[] = "Repeatmode: track and playlist"; - const char modificatorAllButtonsLocked[] = "Modificator: locking all keys via RFID-tag."; - const char modificatorAllButtonsUnlocked[] = "Modificator: unlocking all keys via RFID-tag."; - const char modificatorSleepd[] = "Modificator: sleep-Timer deactivated."; - const char modificatorSleepTimer15[] = "Modificator: sleep-Timer enabled via RFID (15 minutes)."; - const char modificatorSleepTimer30[] = "Modificator: sleep-Timer enabled via RFID (30 minutes)."; - const char modificatorSleepTimer60[] = "Modificator: sleep-Timer enabled via RFID (60 minutes)."; - const char modificatorSleepTimer120[] = "Modificator: sleep-Timer enabled via RFID (2 hours)."; - const char ledsDimmedToNightmode[] = "Dimmed LEDs to nightmode."; - const char ledsDimmedToInitialValue[] = "Dimmed LEDs to initial value."; - const char modificatorNotallowedWhenIdle[] = "Modificator cannot be applied while playlist is inactive."; - const char modificatorSleepAtEOT[] = "Modificator: adjusted sleep-timer to after end of current track."; - const char modificatorSleepAtEOTd[] = "Modificator: disabled sleep-timer after end of current track."; - const char modificatorSleepAtEOP[] = "Modificator: adjusted sleep-timer to after end of playlist."; - const char modificatorSleepAtEOPd[] = "Modificator: disabled sleep-timer after end of playlist."; - const char modificatorAllTrackAlphSortedLoop[] = "Modificator: adjusted to all tracks (in alph. order) as infinite loop."; - const char modificatorAllTrackRandomLoop[] = "Modificator: adjusted to all tracks (in random order) as infinite loop."; - const char modificatorCurTrackLoop[] = "Modificator: adjusted to current track as infinite loop."; - const char modificatorCurAudiobookLoop[] = "Modificator: adjusted to current audiobook as infinite loop."; - const char modificatorPlaylistLoopActive[] = "Modificator: adjusted to all tracks as infinite loop."; - const char modificatorPlaylistLoopDeactive[] = "Modificator: disabled all tracks as infinite loop."; - const char modificatorTrackActive[] = "Modificator: adjusted to current track as infinite loop."; - const char modificatorTrackDeactive[] = "Modificator: disabled current track as infinite loop."; - const char modificatorNotAllowed[] = "Unable to apply modificator."; - const char modificatorLoopRev[] = "Modificator: infinite loop ended."; - const char modificatorDoesNotExist[] = "This type of card-modificator does not exist %d!"; - const char errorOccuredNvs[] = "Error occured while reading from NVS!"; - const char statementsReceivedByServer[] = "Data received from server"; - const char apReady[] = "Started wifi-access-point"; - const char httpReady[] = "Started HTTP-server."; - const char unableToMountSd[] = "Unable to mount sd-card."; - const char unableToCreateVolQ[] = "Unable to create volume-queue."; - const char unableToCreateRfidQ[] = "Unable to create RFID-queue."; - const char unableToCreateMgmtQ[] = "Unable to play-management-queue."; - const char unableToCreatePlayQ[] = "Unable to create track-queue.."; - const char initialBrightnessfromNvs[] = "Restoring initial LED-brightness from NVS: %u"; - const char wroteInitialBrightnessToNvs[] = "Storing initial LED-brightness to NVS."; - const char restoredInitialBrightnessForNmFromNvs[] = "Restored LED-brightness for nightmode from NVS: %u"; - const char wroteNmBrightnessToNvs[] = "Stored LED-brightness for nightmode to NVS."; - const char wroteFtpUserToNvs[] = "Stored FTP-user to NVS."; - const char restoredFtpUserFromNvs[] = "Restored FTP-user from NVS: %s"; - const char wroteFtpPwdToNvs[] = "Stored FTP-password to NVS."; - const char restoredFtpPwdFromNvs[] = "Restored FTP-password from NVS: %s"; - const char restoredMaxInactivityFromNvs[] = "Restored maximum inactivity-time from NVS: %u minutes"; - const char wroteMaxInactivityToNvs[] = "Stored maximum inactivity-time to NVS."; - const char restoredInitialLoudnessFromNvs[] = "Restored initial volume from NVS: %u"; - const char wroteInitialLoudnessToNvs[] = "Stored initial volume to NVS."; - const char restoredMaxLoudnessForSpeakerFromNvs[] = "Restored maximum volume for speaker from NVS: %u"; - const char restoredMaxLoudnessForHeadphoneFromNvs[] = "Restored maximum volume for headphone from NVS: %u"; - const char wroteMaxLoudnessForSpeakerToNvs[] = "Wrote maximum volume for speaker to NVS."; - const char wroteMaxLoudnessForHeadphoneToNvs[] = "Wrote maximum volume for headphone to NVS."; - const char maxVolumeSet[] = "Maximum volume set to: %u"; - const char wroteMqttFlagToNvs[] = "Stored MQTT-flag to NVS."; - const char restoredMqttActiveFromNvs[] = "Restored MQTT-flag (enabled) from NVS: %u"; - const char restoredMqttDeactiveFromNvs[] = "Restored MQTT-flag (disabled) from NVS: %u"; - const char wroteMqttClientIdToNvs[] = "Stored MQTT-clientid to NVS."; - const char restoredMqttClientIdFromNvs[] = "Restored MQTT-clientid from NVS: %s"; - const char wroteMqttServerToNvs[] = "Stored MQTT-server to NVS."; - const char restoredMqttServerFromNvs[] = "Restored MQTT-Server from NVS: %s"; - const char wroteMqttUserToNvs[] = "Stored MQTT-user to NVS."; - const char restoredMqttUserFromNvs[] = "Restored MQTT-user from NVS: %s"; - const char wroteMqttPwdToNvs[] = "Stored MQTT-password to NVS."; - const char restoredMqttPwdFromNvs[] = "Restored MQTT-password from NVS: %s"; - const char restoredMqttPortFromNvs[] = "Restored MQTT-port from NVS: %u"; - const char mqttWithPwd[] = "Try to connect to MQTT-server with user und password"; - const char mqttWithoutPwd[] = "Try to connect to MQTT-server without user und password"; - const char ssidNotFoundInNvs[] = "Unable to find SSID to NVS."; - const char wifiStaticIpConfigNotFoundInNvs[] = "Unable to find wifi-ip-configuration to NVS."; - const char wifiHostnameNotSet[] = "Unable to find hostname-configuration to NVS."; - const char mqttConnFailed[] = "Unable to establish mqtt-connection, trying again: rc=%i (%d / %d)"; - const char restoredHostnameFromNvs[] = "Restored hostname from NVS: %s"; - const char currentVoltageMsg[] = "Current battery-voltage: %.2f V"; - const char currentChargeMsg[] = "Current battery charge: %.2f %%"; - const char batteryCurrentMsg[] = "Power usage (Battery): %.2f mA"; - const char batteryTempMsg[] = "Battery temperature: %.2f °C"; - const char batteryCyclesMsg[] = "Seen battery cycles: %.2f"; - const char batteryLowMsg[] = "Battery charge low"; - const char batteryCriticalMsg[] = "Battery charge critical. Will go to deepsleep..."; - const char sdBootFailedDeepsleep[] = "Failed to boot due to SD. Will go to deepsleep..."; - const char wifiEnabledMsg[] = "WiFi will be enabled."; - const char wifiDisabledMsg[] = "WiFi will be disabled ."; - const char voltageIndicatorLowFromNVS[] = "Restored lower voltage-level for Neopixel-display from NVS: %.2fV"; - const char voltageIndicatorHighFromNVS[] = "Restored upper voltage-level for Neopixel-display from NVS: %.2fV"; - const char batteryCheckIntervalFromNVS[] = "Restored interval of battery-measurement or Neopixel-display from NVS: %u minutes"; - const char warningLowVoltageFromNVS[] = "Restored low battery-voltage-level for warning via Neopixel from NVS: %.2fV"; - const char warningCriticalVoltageFromNVS[] = "Restored critical battery-voltage-level for warning via Neopixel from NVS: %.2fV"; - const char batteryLowFromNVS[] = "Restored low battery level from NVS: %.2f %%"; - const char batteryCriticalFromNVS[] = "Restored critical battery level from NVS: %.2f %%"; - const char unableToRestoreLastRfidFromNVS[] = "Unable to restore last RFID from NVS"; - const char restoredLastRfidFromNVS[] = "Restored last RFID from NVS: %s"; - const char failedOpenFileForWrite[] = "Failed to open file for writing"; - const char fileWritten[] = "File written: %s => %zu bytes in %lu ms (%lu kiB/s)"; - const char writeFailed[] = "Write failed"; - const char writingFile[] = "Writing file: %s"; - const char failedToOpenFileForAppending[] = "Failed to open file for appending"; - const char listingDirectory[] = "Listing directory"; - const char failedToOpenDirectory[] = "Failed to open directory"; - const char notADirectory[] = "Not a directory"; - const char sdMountedMmc1BitMode[] = "SD card mounted in SD-MMC 1-Bit mode..."; - const char sdMountedSpiMode[] = "Mounting SD card in SPI-mode..."; - const char restartWebsite[] = "

ESPuino is being restarted...
Back to last page.

"; - const char shutdownWebsite[] = "Der ESPuino is being shutdown..."; - const char mqttMsgReceived[] = "MQTT-message received: [Topic: %s] [Command: %s]"; - const char trackPausedAtPos[] = "Track paused at position: %u (%u)"; - const char freeHeapWithoutFtp[] = "Free heap before FTP-allocation: %u"; - const char freeHeapWithFtp[] = "Free heap after FTP-allocation: %u"; - const char freeHeapAfterSetup[] = "Free heap after setup"; - const char ftpServerStarted[] = "FTP-Server started"; - const char tryStaticIpConfig[] = "Performing IP-configuration..."; - const char staticIPConfigFailed[] = "IP-configuration failed"; - const char wakeUpRfidNoIso14443[] = "Wakeup caused by low power card-detection. RF-field changed but no ISO-14443 card on reader was found. So I'll return back to sleep now..."; - const char lowPowerCardSuccess[] = "Switch to low power card-detection: success"; - const char rememberLastVolume[] = "Restored volume used before last shutdown. This overwrites the initial volume configured via webgui."; - const char unableToStartFtpServer[] = "FTP-server cannot be started. This is because FTP-service is already active or because WiFi is unavailable."; - const char unableToTellIpAddress[] = "IP-address can't be announced as there's no WiFi-connection available."; - const char unableToTellTime[] = "Time can't be announced as there's no WiFi-connection available."; - const char newPlayModeStereo[] = "New mode: stereo"; - const char newPlayModeMono[] = "New mode: mono"; - const char portExpanderFound[] = "Port-expander found"; - const char portExpanderNotFound[] = "Unable to detect port-expander"; - const char portExpanderInterruptEnabled[] = "Enabled interrupt-handling for port-expander"; - const char playlistGen[] = "Playlist-generation"; - const char bootLoopDetected[] = "Bootloop detected! Last RFID won't be restored."; - const char noBootLoopDetected[] = "No bootloop detected. Great :-)"; - const char importCountNokNvs[] = "Number of invalid import-entries: %u"; - const char errorReadingTmpfile[] = "Error occured while reading from import-tmpfile"; - const char errorWritingTmpfile[] = "Error occured while writing to import-tmpfile"; - const char eraseRfidNvs[] = "NVS-RFID-assignments are being deleted..."; - const char fwStart[] = "Starting firmware-update via OTA..."; - const char fwEnd[] = "Firmware-update finished"; - const char otaNotSupported[] = "Firmware-update isn't supported by this ESPuino!"; - const char otaNotSupportedWebsite[] = "

FFirmware-update isn't supported by this ESPuino!
Back to last page.

"; - const char noPlaylist[] = "No active playlist."; - const char rfidTagRemoved[] = "RFID-tag removed"; - const char rfidTagReapplied[] = "RFID-tag reapplied"; - const char ftpEnableTooLate[] = "FTP can only be enabled within the first 30s after ESPuino-start. Child-protection :-)"; - const char syncingViaNtp[] = "Getting current time via NTP..."; - const char ntpGotTime[] = "Received date/time from NTP server: %02d.%02d.%4d, %02d:%02d:%02d"; - const char ntpFailed[] = "Failed to obtain NTP time"; - const char sdInfo[] = "SD card size / free space: %llu MB / %llu MB"; - const char paOn[] = "Loudspeaker on"; - const char paOff[] = "Loudspeaker off"; - const char hpOn[] = "Headphones on"; - const char hpOff[] = "Headphones off"; - const char webTxCanceled[] = "Webtransfer canceled due to inactivity-timer."; - const char tryToPickRandomDir[] = "Try to pick randon subdirectory out of: %s"; - const char pickedRandomDir[] = "Randomly picked subdirectory: %s"; - const char wrongWakeUpGpio[] = "GPIO choosen as wakeup-pin isn't of type RTC and that reason for can't wake up ESP32! (GPIO: %u)"; - const char currentlyPlaying[] = "'%s' is being played (%d of %d)"; - const char secondsJumpForward[] = "Jumped %d seconds forwards"; - const char secondsJumpBackward[] = "Jumped %d seconds backward"; - const char wroteLastTrackToNvs[] = "Write '%s' to NVS for RFID-Card-ID %s with playmode %d and last track %u"; - const char wifiConnectionInProgress[] = "Try to connect to WiFi with SSID '%s'..."; - const char wifiConnectionSuccess[] = "Connected with WiFi '%s' (signal strength: %d dBm, channel: %d, BSSID: %s)"; - const char wifiCurrentIp[] = "Current IP: %s"; - const char jsonErrorMsg[] = "deserializeJson() failed: %s"; - const char wifiDeleteNetwork[] = "Deleting saved WiFi %s"; - const char wifiNetworkLoaded[] = "Loaded SSID %d from NVS: %s"; - const char wifiTooManyNetworks[] = "Number of networks in NVS is %d, but that's more than the allowed %d"; - const char wifiAddTooManyNetworks[] = "No space left to add another WiFi network!"; - const char wifiAddNetwork[] = "Add WiFi network %s"; - const char wifiUpdateNetwork[] = "Update WiFi network %s"; - const char wifiScanResult[] = "Found WiFi with SSID %s and signal strength %d dBm on channel %d, BSSID %s."; - const char cantConnectToWifi[] = "Failed to connect to WiFi."; - const char wifiSetLastSSID[] = "Write last successful SSID to NVS for WiFi fast-path: %s"; - const char mDNSStarted[] = "mDNS started: http://%s.local"; - const char mDNSFailed[] = "mDNS failure, hostname: %s"; +const char tryConnectMqttS[] = "Trying to connect to MQTT-broker: %s"; +const char mqttOk[] = "MQTT-connection established."; +const char sleepTimerEOP[] = "Sleep-timer: after last track of playlist."; +const char sleepTimerEOT[] = "Sleep-timer: after end of current track."; +const char sleepTimerStop[] = "Sleep-timer has been disabled."; +const char sleepTimerEO5[] = "Sleep-timer: after five track or end of playlist - whatever is reached first"; +const char sleepTimerAlreadyStopped[] = "sleep-timer is already disabled."; +const char sleepTimerSetTo[] = "sleep-timer adjusted to %u minute(s)"; +const char allowButtons[] = "Unlocking all keys."; +const char lockButtons[] = "Locking all keys."; +const char noPlaylistNotAllowedMqtt[] = "Playmode cannot be adjusted to 'no playlist' via MQTT."; +const char playmodeChangedMQtt[] = "Playlist adjusted via MQTT."; +const char noPlaymodeChangeIfIdle[] = "Playlist cannot be adjusted while no playlist is active."; +const char noValidTopic[] = "No valid MQTT-topic: %s"; +const char freePtr[] = "Releasing Pointer: %s (0x%04x)"; +const char freeMemory[] = "Free memory: %u Bytes"; +const char writeEntryToNvs[] = "[%u] Storing data to NVS: %s => %s"; +const char freeMemoryAfterFree[] = "Free memory after cleaning: %u Bytes"; +const char releaseMemoryOfOldPlaylist[] = "Releasing memory of old playlist (Free memory: %u Bytes)."; +const char dirOrFileDoesNotExist[] = "File of directory does not exist: %s"; +const char unableToAllocateMemForPlaylist[] = "Unable to allocate memory for playlist!"; +const char unableToAllocateMem[] = "Unable to allocate memory!"; +const char fileModeDetected[] = "File-mode detected."; +const char nameOfFileFound[] = "File found: %s"; +const char reallocCalled[] = "Reallocated memory."; +const char unableToAllocateMemForLinearPlaylist[] = "Unable to allocate memory for linear playlist!"; +const char numberOfValidFiles[] = "Number of valid files/webstreams: %u"; +const char newLoudnessReceivedQueue[] = "New volume received via queue: %u"; +const char newCntrlReceivedQueue[] = "Control-command received via queue: %u"; +const char newPlaylistReceived[] = "New playlist received with %d track(s)"; +const char repeatTrackDueToPlaymode[] = "Repeating track due to playmode configured."; +const char repeatPlaylistDueToPlaymode[] = "Repeating playlist due to playmode configured."; +const char cmndStop[] = "Command: stop"; +const char cmndPause[] = "Command: pause"; +const char cmndResumeFromPause[] = "Command: resume"; +const char cmndNextTrack[] = "Command: next track"; +const char cmndPrevTrack[] = "Command: previous track"; +const char cmndFirstTrack[] = "Command: first track of playlist"; +const char cmndLastTrack[] = "Command: last track of playlist"; +const char cmndDoesNotExist[] = "Command requested does not exist."; +const char lastTrackAlreadyActive[] = "Already playing last track."; +const char trackStartAudiobook[] = "Starting track in playmode from the very beginning."; +const char trackStart[] = "Starting track from the very beginning."; +const char trackChangeWebstream[] = "Playing from the very beginning is not possible while webradio-mode is active."; +const char endOfPlaylistReached[] = "Reached end of playlist."; +const char trackStartatPos[] = "Starting track at position %u"; +const char waitingForTaskQueues[] = "Task Queue for RFID does not exist yet, waiting..."; +const char rfidScannerReady[] = "RFID-tags can now be applied..."; +const char rfidTagDetected[] = "RFID-tag detected: %s"; +const char rfid15693TagDetected[] = "RFID-ta (ISO-15693) detected: "; +const char rfidTagReceived[] = "RFID-tag received"; +const char dontAccepctSameRfid[] = "Reapplied same rfid-tag - rejected! (%s)"; +const char rfidTagUnknownInNvs[] = "RFID-tag is unkown to NVS."; +const char goToSleepDueToIdle[] = "Going to deepsleep due to inactivity-timer..."; +const char goToSleepDueToTimer[] = "Going to deepsleep due to sleep timer..."; +const char goToSleepNow[] = "Going to deepsleep now!"; +const char maxLoudnessReached[] = "Already reached max volume!"; +const char minLoudnessReached[] = "Already reached min volume!"; +const char errorOccured[] = "Error occured!"; +const char noMp3FilesInDir[] = "Directory does not contain mp3-files."; +const char modeSingleTrack[] = "Mode: Single track"; +const char modeSingleTrackLoop[] = "Mode: single track as infinite loop"; +const char modeSingleTrackRandom[] = "Mode: single track (random) of directory"; +const char modeSingleAudiobook[] = "Mode: audiobook"; +const char modeSingleAudiobookLoop[] = "Mode: audiobook as infinite loop"; +const char modeAllTrackAlphSorted[] = "Mode: all tracks (in alph. order) of directory '%s'"; +const char modeAllTrackRandom[] = "Mode: all tracks (in random. order) of directory '%s"; +const char modeAllTrackAlphSortedLoop[] = "Mode: all tracks (in alph. order) of directory as infinite loop"; +const char modeAllTrackRandomLoop[] = "Mode: all tracks (in random order) of directory as infinite loop"; +const char modeWebstream[] = "Mode: webstream"; +const char modeWebstreamM3u[] = "Mode: Webstream (local .m3u-file)"; +const char webstreamNotAvailable[] = "Unable to access webstream as no wifi-connection is available!"; +const char modeDoesNotExist[] = "Playmode does not exist!"; +const char modeRepeatNone[] = "Repeatmode: no repeat"; +const char modeRepeatTrack[] = "Repeatmode: current track"; +const char modeRepeatPlaylist[] = "Repeatmode: whole playlist"; +const char modeRepeatTracknPlaylist[] = "Repeatmode: track and playlist"; +const char modificatorAllButtonsLocked[] = "Modificator: locking all keys via RFID-tag."; +const char modificatorAllButtonsUnlocked[] = "Modificator: unlocking all keys via RFID-tag."; +const char modificatorSleepd[] = "Modificator: sleep-Timer deactivated."; +const char modificatorSleepTimer15[] = "Modificator: sleep-Timer enabled via RFID (15 minutes)."; +const char modificatorSleepTimer30[] = "Modificator: sleep-Timer enabled via RFID (30 minutes)."; +const char modificatorSleepTimer60[] = "Modificator: sleep-Timer enabled via RFID (60 minutes)."; +const char modificatorSleepTimer120[] = "Modificator: sleep-Timer enabled via RFID (2 hours)."; +const char ledsDimmedToNightmode[] = "Dimmed LEDs to nightmode."; +const char ledsDimmedToInitialValue[] = "Dimmed LEDs to initial value."; +const char modificatorNotallowedWhenIdle[] = "Modificator cannot be applied while playlist is inactive."; +const char modificatorSleepAtEOT[] = "Modificator: adjusted sleep-timer to after end of current track."; +const char modificatorSleepAtEOTd[] = "Modificator: disabled sleep-timer after end of current track."; +const char modificatorSleepAtEOP[] = "Modificator: adjusted sleep-timer to after end of playlist."; +const char modificatorSleepAtEOPd[] = "Modificator: disabled sleep-timer after end of playlist."; +const char modificatorAllTrackAlphSortedLoop[] = "Modificator: adjusted to all tracks (in alph. order) as infinite loop."; +const char modificatorAllTrackRandomLoop[] = "Modificator: adjusted to all tracks (in random order) as infinite loop."; +const char modificatorCurTrackLoop[] = "Modificator: adjusted to current track as infinite loop."; +const char modificatorCurAudiobookLoop[] = "Modificator: adjusted to current audiobook as infinite loop."; +const char modificatorPlaylistLoopActive[] = "Modificator: adjusted to all tracks as infinite loop."; +const char modificatorPlaylistLoopDeactive[] = "Modificator: disabled all tracks as infinite loop."; +const char modificatorTrackActive[] = "Modificator: adjusted to current track as infinite loop."; +const char modificatorTrackDeactive[] = "Modificator: disabled current track as infinite loop."; +const char modificatorNotAllowed[] = "Unable to apply modificator."; +const char modificatorLoopRev[] = "Modificator: infinite loop ended."; +const char modificatorDoesNotExist[] = "This type of card-modificator does not exist %d!"; +const char errorOccuredNvs[] = "Error occured while reading from NVS!"; +const char statementsReceivedByServer[] = "Data received from server"; +const char apReady[] = "Started wifi-access-point"; +const char httpReady[] = "Started HTTP-server."; +const char unableToMountSd[] = "Unable to mount sd-card."; +const char unableToCreateVolQ[] = "Unable to create volume-queue."; +const char unableToCreateRfidQ[] = "Unable to create RFID-queue."; +const char unableToCreateMgmtQ[] = "Unable to play-management-queue."; +const char unableToCreatePlayQ[] = "Unable to create track-queue.."; +const char initialBrightnessfromNvs[] = "Restoring initial LED-brightness from NVS: %u"; +const char wroteInitialBrightnessToNvs[] = "Storing initial LED-brightness to NVS."; +const char restoredInitialBrightnessForNmFromNvs[] = "Restored LED-brightness for nightmode from NVS: %u"; +const char wroteNmBrightnessToNvs[] = "Stored LED-brightness for nightmode to NVS."; +const char wroteFtpUserToNvs[] = "Stored FTP-user to NVS."; +const char restoredFtpUserFromNvs[] = "Restored FTP-user from NVS: %s"; +const char wroteFtpPwdToNvs[] = "Stored FTP-password to NVS."; +const char restoredFtpPwdFromNvs[] = "Restored FTP-password from NVS: %s"; +const char restoredMaxInactivityFromNvs[] = "Restored maximum inactivity-time from NVS: %u minutes"; +const char wroteMaxInactivityToNvs[] = "Stored maximum inactivity-time to NVS."; +const char restoredInitialLoudnessFromNvs[] = "Restored initial volume from NVS: %u"; +const char wroteInitialLoudnessToNvs[] = "Stored initial volume to NVS."; +const char restoredMaxLoudnessForSpeakerFromNvs[] = "Restored maximum volume for speaker from NVS: %u"; +const char restoredMaxLoudnessForHeadphoneFromNvs[] = "Restored maximum volume for headphone from NVS: %u"; +const char wroteMaxLoudnessForSpeakerToNvs[] = "Wrote maximum volume for speaker to NVS."; +const char wroteMaxLoudnessForHeadphoneToNvs[] = "Wrote maximum volume for headphone to NVS."; +const char maxVolumeSet[] = "Maximum volume set to: %u"; +const char wroteMqttFlagToNvs[] = "Stored MQTT-flag to NVS."; +const char restoredMqttActiveFromNvs[] = "Restored MQTT-flag (enabled) from NVS: %u"; +const char restoredMqttDeactiveFromNvs[] = "Restored MQTT-flag (disabled) from NVS: %u"; +const char wroteMqttClientIdToNvs[] = "Stored MQTT-clientid to NVS."; +const char restoredMqttClientIdFromNvs[] = "Restored MQTT-clientid from NVS: %s"; +const char wroteMqttServerToNvs[] = "Stored MQTT-server to NVS."; +const char restoredMqttServerFromNvs[] = "Restored MQTT-Server from NVS: %s"; +const char wroteMqttUserToNvs[] = "Stored MQTT-user to NVS."; +const char restoredMqttUserFromNvs[] = "Restored MQTT-user from NVS: %s"; +const char wroteMqttPwdToNvs[] = "Stored MQTT-password to NVS."; +const char restoredMqttPwdFromNvs[] = "Restored MQTT-password from NVS: %s"; +const char restoredMqttPortFromNvs[] = "Restored MQTT-port from NVS: %u"; +const char mqttWithPwd[] = "Try to connect to MQTT-server with user und password"; +const char mqttWithoutPwd[] = "Try to connect to MQTT-server without user und password"; +const char ssidNotFoundInNvs[] = "Unable to find SSID to NVS."; +const char wifiStaticIpConfigNotFoundInNvs[] = "Unable to find wifi-ip-configuration to NVS."; +const char wifiHostnameNotSet[] = "Unable to find hostname-configuration to NVS."; +const char mqttConnFailed[] = "Unable to establish mqtt-connection, trying again: rc=%i (%d / %d)"; +const char restoredHostnameFromNvs[] = "Restored hostname from NVS: %s"; +const char currentVoltageMsg[] = "Current battery-voltage: %.2f V"; +const char currentChargeMsg[] = "Current battery charge: %.2f %%"; +const char batteryCurrentMsg[] = "Power usage (Battery): %.2f mA"; +const char batteryTempMsg[] = "Battery temperature: %.2f °C"; +const char batteryCyclesMsg[] = "Seen battery cycles: %.2f"; +const char batteryLowMsg[] = "Battery charge low"; +const char batteryCriticalMsg[] = "Battery charge critical. Will go to deepsleep..."; +const char sdBootFailedDeepsleep[] = "Failed to boot due to SD. Will go to deepsleep..."; +const char wifiEnabledMsg[] = "WiFi will be enabled."; +const char wifiDisabledMsg[] = "WiFi will be disabled ."; +const char voltageIndicatorLowFromNVS[] = "Restored lower voltage-level for Neopixel-display from NVS: %.2fV"; +const char voltageIndicatorHighFromNVS[] = "Restored upper voltage-level for Neopixel-display from NVS: %.2fV"; +const char batteryCheckIntervalFromNVS[] = "Restored interval of battery-measurement or Neopixel-display from NVS: %u minutes"; +const char warningLowVoltageFromNVS[] = "Restored low battery-voltage-level for warning via Neopixel from NVS: %.2fV"; +const char warningCriticalVoltageFromNVS[] = "Restored critical battery-voltage-level for warning via Neopixel from NVS: %.2fV"; +const char batteryLowFromNVS[] = "Restored low battery level from NVS: %.2f %%"; +const char batteryCriticalFromNVS[] = "Restored critical battery level from NVS: %.2f %%"; +const char unableToRestoreLastRfidFromNVS[] = "Unable to restore last RFID from NVS"; +const char restoredLastRfidFromNVS[] = "Restored last RFID from NVS: %s"; +const char failedOpenFileForWrite[] = "Failed to open file for writing"; +const char fileWritten[] = "File written: %s => %zu bytes in %lu ms (%lu kiB/s)"; +const char writeFailed[] = "Write failed"; +const char writingFile[] = "Writing file: %s"; +const char failedToOpenFileForAppending[] = "Failed to open file for appending"; +const char listingDirectory[] = "Listing directory"; +const char failedToOpenDirectory[] = "Failed to open directory"; +const char notADirectory[] = "Not a directory"; +const char sdMountedMmc1BitMode[] = "SD card mounted in SD-MMC 1-Bit mode..."; +const char sdMountedSpiMode[] = "Mounting SD card in SPI-mode..."; +const char restartWebsite[] = "

ESPuino is being restarted...
Back to last page.

"; +const char shutdownWebsite[] = "Der ESPuino is being shutdown..."; +const char mqttMsgReceived[] = "MQTT-message received: [Topic: %s] [Command: %s]"; +const char trackPausedAtPos[] = "Track paused at position: %u (%u)"; +const char freeHeapWithoutFtp[] = "Free heap before FTP-allocation: %u"; +const char freeHeapWithFtp[] = "Free heap after FTP-allocation: %u"; +const char freeHeapAfterSetup[] = "Free heap after setup"; +const char ftpServerStarted[] = "FTP-Server started"; +const char tryStaticIpConfig[] = "Performing IP-configuration..."; +const char staticIPConfigFailed[] = "IP-configuration failed"; +const char wakeUpRfidNoIso14443[] = "Wakeup caused by low power card-detection. RF-field changed but no ISO-14443 card on reader was found. So I'll return back to sleep now..."; +const char lowPowerCardSuccess[] = "Switch to low power card-detection: success"; +const char rememberLastVolume[] = "Restored volume used before last shutdown. This overwrites the initial volume configured via webgui."; +const char unableToStartFtpServer[] = "FTP-server cannot be started. This is because FTP-service is already active or because WiFi is unavailable."; +const char unableToTellIpAddress[] = "IP-address can't be announced as there's no WiFi-connection available."; +const char unableToTellTime[] = "Time can't be announced as there's no WiFi-connection available."; +const char newPlayModeStereo[] = "New mode: stereo"; +const char newPlayModeMono[] = "New mode: mono"; +const char portExpanderFound[] = "Port-expander found"; +const char portExpanderNotFound[] = "Unable to detect port-expander"; +const char portExpanderInterruptEnabled[] = "Enabled interrupt-handling for port-expander"; +const char playlistGen[] = "Playlist-generation"; +const char bootLoopDetected[] = "Bootloop detected! Last RFID won't be restored."; +const char noBootLoopDetected[] = "No bootloop detected. Great :-)"; +const char importCountNokNvs[] = "Number of invalid import-entries: %u"; +const char errorReadingTmpfile[] = "Error occured while reading from import-tmpfile"; +const char errorWritingTmpfile[] = "Error occured while writing to import-tmpfile"; +const char eraseRfidNvs[] = "NVS-RFID-assignments are being deleted..."; +const char fwStart[] = "Starting firmware-update via OTA..."; +const char fwEnd[] = "Firmware-update finished"; +const char otaNotSupported[] = "Firmware-update isn't supported by this ESPuino!"; +const char otaNotSupportedWebsite[] = "

FFirmware-update isn't supported by this ESPuino!
Back to last page.

"; +const char noPlaylist[] = "No active playlist."; +const char rfidTagRemoved[] = "RFID-tag removed"; +const char rfidTagReapplied[] = "RFID-tag reapplied"; +const char ftpEnableTooLate[] = "FTP can only be enabled within the first 30s after ESPuino-start. Child-protection :-)"; +const char syncingViaNtp[] = "Getting current time via NTP..."; +const char ntpGotTime[] = "Received date/time from NTP server: %02d.%02d.%4d, %02d:%02d:%02d"; +const char ntpFailed[] = "Failed to obtain NTP time"; +const char sdInfo[] = "SD card size / free space: %llu MB / %llu MB"; +const char paOn[] = "Loudspeaker on"; +const char paOff[] = "Loudspeaker off"; +const char hpOn[] = "Headphones on"; +const char hpOff[] = "Headphones off"; +const char webTxCanceled[] = "Webtransfer canceled due to inactivity-timer."; +const char tryToPickRandomDir[] = "Try to pick randon subdirectory out of: %s"; +const char pickedRandomDir[] = "Randomly picked subdirectory: %s"; +const char wrongWakeUpGpio[] = "GPIO choosen as wakeup-pin isn't of type RTC and that reason for can't wake up ESP32! (GPIO: %u)"; +const char currentlyPlaying[] = "'%s' is being played (%d of %d)"; +const char secondsJumpForward[] = "Jumped %d seconds forwards"; +const char secondsJumpBackward[] = "Jumped %d seconds backward"; +const char wroteLastTrackToNvs[] = "Write '%s' to NVS for RFID-Card-ID %s with playmode %d and last track %u"; +const char wifiConnectionInProgress[] = "Try to connect to WiFi with SSID '%s'..."; +const char wifiConnectionSuccess[] = "Connected with WiFi '%s' (signal strength: %d dBm, channel: %d, BSSID: %s)"; +const char wifiCurrentIp[] = "Current IP: %s"; +const char jsonErrorMsg[] = "deserializeJson() failed: %s"; +const char wifiDeleteNetwork[] = "Deleting saved WiFi %s"; +const char wifiNetworkLoaded[] = "Loaded SSID %d from NVS: %s"; +const char wifiTooManyNetworks[] = "Number of networks in NVS is %d, but that's more than the allowed %d"; +const char wifiAddTooManyNetworks[] = "No space left to add another WiFi network!"; +const char wifiAddNetwork[] = "Add WiFi network %s"; +const char wifiUpdateNetwork[] = "Update WiFi network %s"; +const char wifiScanResult[] = "Found WiFi with SSID %s and signal strength %d dBm on channel %d, BSSID %s."; +const char cantConnectToWifi[] = "Failed to connect to WiFi."; +const char wifiSetLastSSID[] = "Write last successful SSID to NVS for WiFi fast-path: %s"; +const char mDNSStarted[] = "mDNS started: http://%s.local"; +const char mDNSFailed[] = "mDNS failure, hostname: %s"; #endif diff --git a/src/MemX.cpp b/src/MemX.cpp index edad521f..91c1c4b9 100644 --- a/src/MemX.cpp +++ b/src/MemX.cpp @@ -1,13 +1,14 @@ #include + #include "MemX.h" // Wraps strdup(). Without PSRAM, strdup is called => so heap is used. // With PSRAM being available, the same is done what strdup() does, but with allocation on PSRAM. -char * x_strdup(const char *_str) { +char *x_strdup(const char *_str) { if (!psramInit()) { return strdup(_str); } else { - char *dst = (char *) ps_malloc(strlen (_str) + 1); + char *dst = (char *) ps_malloc(strlen(_str) + 1); if (dst == NULL) { return NULL; } @@ -17,7 +18,7 @@ char * x_strdup(const char *_str) { } // Wraps ps_malloc() and malloc(). Selection depends on whether PSRAM is available or not. -char * x_malloc(uint32_t _allocSize) { +char *x_malloc(uint32_t _allocSize) { if (psramInit()) { return (char *) ps_malloc(_allocSize); } else { @@ -25,9 +26,8 @@ char * x_malloc(uint32_t _allocSize) { } } - // Wraps ps_calloc() and calloc(). Selection depends on whether PSRAM is available or not. -char * x_calloc(uint32_t _allocSize, uint32_t _unitSize) { +char *x_calloc(uint32_t _allocSize, uint32_t _unitSize) { if (psramInit()) { return (char *) ps_calloc(_allocSize, _unitSize); } else { diff --git a/src/Mqtt.cpp b/src/Mqtt.cpp index f0669547..17161ac3 100644 --- a/src/Mqtt.cpp +++ b/src/Mqtt.cpp @@ -1,16 +1,19 @@ #include -#include #include "settings.h" + #include "Mqtt.h" + #include "AudioPlayer.h" #include "Led.h" #include "Log.h" #include "MemX.h" -#include "System.h" #include "Queues.h" +#include "System.h" #include "Wlan.h" #include "revision.h" +#include + #ifdef MQTT_ENABLE #define MQTT_SOCKET_TIMEOUT 1 // https://github.com/knolleary/pubsubclient/issues/403 #include @@ -18,120 +21,120 @@ // MQTT-helper #ifdef MQTT_ENABLE - static WiFiClient Mqtt_WifiClient; - static PubSubClient Mqtt_PubSubClient(Mqtt_WifiClient); - // Please note: all of them are defaults that can be changed later via GUI - String gMqttClientId = DEVICE_HOSTNAME; // ClientId for the MQTT-server, must be server wide unique (if not found in NVS this one will be taken) - String gMqttServer = "192.168.2.43"; // IP-address of MQTT-server (if not found in NVS this one will be taken) - String gMqttUser = "mqtt-user"; // MQTT-user - String gMqttPassword = "mqtt-password"; // MQTT-password - uint16_t gMqttPort = 1883; // MQTT-Port +static WiFiClient Mqtt_WifiClient; +static PubSubClient Mqtt_PubSubClient(Mqtt_WifiClient); +// Please note: all of them are defaults that can be changed later via GUI +String gMqttClientId = DEVICE_HOSTNAME; // ClientId for the MQTT-server, must be server wide unique (if not found in NVS this one will be taken) +String gMqttServer = "192.168.2.43"; // IP-address of MQTT-server (if not found in NVS this one will be taken) +String gMqttUser = "mqtt-user"; // MQTT-user +String gMqttPassword = "mqtt-password"; // MQTT-password +uint16_t gMqttPort = 1883; // MQTT-Port #endif // MQTT static bool Mqtt_Enabled = true; #ifdef MQTT_ENABLE - static void Mqtt_ClientCallback(const char *topic, const byte *payload, uint32_t length); - static bool Mqtt_Reconnect(void); - static void Mqtt_PostWiFiRssi(void); -#endif +static void Mqtt_ClientCallback(const char *topic, const byte *payload, uint32_t length); +static bool Mqtt_Reconnect(void); +static void Mqtt_PostWiFiRssi(void); +#endif void Mqtt_Init() { - #ifdef MQTT_ENABLE - // Get MQTT-enable from NVS - uint8_t nvsEnableMqtt = gPrefsSettings.getUChar("enableMQTT", 99); - switch (nvsEnableMqtt) { - case 99: - gPrefsSettings.putUChar("enableMQTT", Mqtt_Enabled); - Log_Println(wroteMqttFlagToNvs, LOGLEVEL_ERROR); - break; - case 1: - Mqtt_Enabled = nvsEnableMqtt; - Log_Printf(LOGLEVEL_INFO, restoredMqttActiveFromNvs, nvsEnableMqtt); - break; - case 0: - Mqtt_Enabled = nvsEnableMqtt; - Log_Printf(LOGLEVEL_INFO, restoredMqttDeactiveFromNvs, nvsEnableMqtt); - break; - } - - // Get MQTT-clientid from NVS - String nvsMqttClientId = gPrefsSettings.getString("mqttClientId", "-1"); - if (!nvsMqttClientId.compareTo("-1")) { - gPrefsSettings.putString("mqttClientId", gMqttClientId); - Log_Println(wroteMqttClientIdToNvs, LOGLEVEL_ERROR); - } else { - gMqttClientId = nvsMqttClientId; - Log_Printf(LOGLEVEL_INFO, restoredMqttClientIdFromNvs, nvsMqttClientId.c_str()); - } - - // Get MQTT-server from NVS - String nvsMqttServer = gPrefsSettings.getString("mqttServer", "-1"); - if (!nvsMqttServer.compareTo("-1")) { - gPrefsSettings.putString("mqttServer", gMqttServer); - Log_Println(wroteMqttServerToNvs, LOGLEVEL_ERROR); - } else { - gMqttServer = nvsMqttServer; - Log_Printf(LOGLEVEL_INFO, restoredMqttServerFromNvs, nvsMqttServer.c_str()); - } - - // Get MQTT-user from NVS - String nvsMqttUser = gPrefsSettings.getString("mqttUser", "-1"); - if (!nvsMqttUser.compareTo("-1")) { - gPrefsSettings.putString("mqttUser", (String)gMqttUser); - Log_Println(wroteMqttUserToNvs, LOGLEVEL_ERROR); - } else { - gMqttUser = nvsMqttUser; - Log_Printf(LOGLEVEL_INFO, restoredMqttUserFromNvs, nvsMqttUser.c_str()); - } - - // Get MQTT-password from NVS - String nvsMqttPassword = gPrefsSettings.getString("mqttPassword", "-1"); - if (!nvsMqttPassword.compareTo("-1")) { - gPrefsSettings.putString("mqttPassword", (String)gMqttPassword); - Log_Println(wroteMqttPwdToNvs, LOGLEVEL_ERROR); - } else { - gMqttPassword = nvsMqttPassword; - Log_Printf(LOGLEVEL_INFO, restoredMqttPwdFromNvs, nvsMqttPassword.c_str()); - } - - // Get MQTT-password from NVS - uint32_t nvsMqttPort = gPrefsSettings.getUInt("mqttPort", 99999); - if (nvsMqttPort == 99999) { - gPrefsSettings.putUInt("mqttPort", gMqttPort); - } else { - gMqttPort = nvsMqttPort; - Log_Printf(LOGLEVEL_INFO, restoredMqttPortFromNvs, gMqttPort); - } - - // Only enable MQTT if requested - if (Mqtt_Enabled) { - Mqtt_PubSubClient.setServer(gMqttServer.c_str(), gMqttPort); - Mqtt_PubSubClient.setCallback(Mqtt_ClientCallback); - } - #else - Mqtt_Enabled = false; - #endif +#ifdef MQTT_ENABLE + // Get MQTT-enable from NVS + uint8_t nvsEnableMqtt = gPrefsSettings.getUChar("enableMQTT", 99); + switch (nvsEnableMqtt) { + case 99: + gPrefsSettings.putUChar("enableMQTT", Mqtt_Enabled); + Log_Println(wroteMqttFlagToNvs, LOGLEVEL_ERROR); + break; + case 1: + Mqtt_Enabled = nvsEnableMqtt; + Log_Printf(LOGLEVEL_INFO, restoredMqttActiveFromNvs, nvsEnableMqtt); + break; + case 0: + Mqtt_Enabled = nvsEnableMqtt; + Log_Printf(LOGLEVEL_INFO, restoredMqttDeactiveFromNvs, nvsEnableMqtt); + break; + } + + // Get MQTT-clientid from NVS + String nvsMqttClientId = gPrefsSettings.getString("mqttClientId", "-1"); + if (!nvsMqttClientId.compareTo("-1")) { + gPrefsSettings.putString("mqttClientId", gMqttClientId); + Log_Println(wroteMqttClientIdToNvs, LOGLEVEL_ERROR); + } else { + gMqttClientId = nvsMqttClientId; + Log_Printf(LOGLEVEL_INFO, restoredMqttClientIdFromNvs, nvsMqttClientId.c_str()); + } + + // Get MQTT-server from NVS + String nvsMqttServer = gPrefsSettings.getString("mqttServer", "-1"); + if (!nvsMqttServer.compareTo("-1")) { + gPrefsSettings.putString("mqttServer", gMqttServer); + Log_Println(wroteMqttServerToNvs, LOGLEVEL_ERROR); + } else { + gMqttServer = nvsMqttServer; + Log_Printf(LOGLEVEL_INFO, restoredMqttServerFromNvs, nvsMqttServer.c_str()); + } + + // Get MQTT-user from NVS + String nvsMqttUser = gPrefsSettings.getString("mqttUser", "-1"); + if (!nvsMqttUser.compareTo("-1")) { + gPrefsSettings.putString("mqttUser", (String) gMqttUser); + Log_Println(wroteMqttUserToNvs, LOGLEVEL_ERROR); + } else { + gMqttUser = nvsMqttUser; + Log_Printf(LOGLEVEL_INFO, restoredMqttUserFromNvs, nvsMqttUser.c_str()); + } + + // Get MQTT-password from NVS + String nvsMqttPassword = gPrefsSettings.getString("mqttPassword", "-1"); + if (!nvsMqttPassword.compareTo("-1")) { + gPrefsSettings.putString("mqttPassword", (String) gMqttPassword); + Log_Println(wroteMqttPwdToNvs, LOGLEVEL_ERROR); + } else { + gMqttPassword = nvsMqttPassword; + Log_Printf(LOGLEVEL_INFO, restoredMqttPwdFromNvs, nvsMqttPassword.c_str()); + } + + // Get MQTT-password from NVS + uint32_t nvsMqttPort = gPrefsSettings.getUInt("mqttPort", 99999); + if (nvsMqttPort == 99999) { + gPrefsSettings.putUInt("mqttPort", gMqttPort); + } else { + gMqttPort = nvsMqttPort; + Log_Printf(LOGLEVEL_INFO, restoredMqttPortFromNvs, gMqttPort); + } + + // Only enable MQTT if requested + if (Mqtt_Enabled) { + Mqtt_PubSubClient.setServer(gMqttServer.c_str(), gMqttPort); + Mqtt_PubSubClient.setCallback(Mqtt_ClientCallback); + } +#else + Mqtt_Enabled = false; +#endif } void Mqtt_Cyclic(void) { - #ifdef MQTT_ENABLE - if (Mqtt_Enabled && Wlan_IsConnected()) { - Mqtt_Reconnect(); - Mqtt_PubSubClient.loop(); - Mqtt_PostWiFiRssi(); - } - #endif +#ifdef MQTT_ENABLE + if (Mqtt_Enabled && Wlan_IsConnected()) { + Mqtt_Reconnect(); + Mqtt_PubSubClient.loop(); + Mqtt_PostWiFiRssi(); + } +#endif } void Mqtt_Exit(void) { - #ifdef MQTT_ENABLE - Log_Println("shutdown MQTT..", LOGLEVEL_NOTICE); - publishMqtt(topicState, "Offline", false); - publishMqtt(topicTrackState, "---", false); - Mqtt_PubSubClient.disconnect(); - #endif +#ifdef MQTT_ENABLE + Log_Println("shutdown MQTT..", LOGLEVEL_NOTICE); + publishMqtt(topicState, "Offline", false); + publishMqtt(topicTrackState, "---", false); + Mqtt_PubSubClient.disconnect(); +#endif } bool Mqtt_IsEnabled(void) { @@ -140,319 +143,319 @@ bool Mqtt_IsEnabled(void) { /* Wrapper-functions for MQTT-publish */ bool publishMqtt(const char *topic, const char *payload, bool retained) { - #ifdef MQTT_ENABLE - if (strcmp(topic, "") != 0) { - if (Mqtt_PubSubClient.connected()) { - Mqtt_PubSubClient.publish(topic, payload, retained); - //delay(100); - return true; - } +#ifdef MQTT_ENABLE + if (strcmp(topic, "") != 0) { + if (Mqtt_PubSubClient.connected()) { + Mqtt_PubSubClient.publish(topic, payload, retained); + // delay(100); + return true; } - #endif + } +#endif return false; } bool publishMqtt(const char *topic, int32_t payload, bool retained) { - #ifdef MQTT_ENABLE - char buf[11]; - snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%d", payload); - return publishMqtt(topic, buf, retained); - #else - return false; - #endif +#ifdef MQTT_ENABLE + char buf[11]; + snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%d", payload); + return publishMqtt(topic, buf, retained); +#else + return false; +#endif } bool publishMqtt(const char *topic, unsigned long payload, bool retained) { - #ifdef MQTT_ENABLE - char buf[11]; - snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%lu", payload); - return publishMqtt(topic, buf, retained); - #else - return false; - #endif +#ifdef MQTT_ENABLE + char buf[11]; + snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%lu", payload); + return publishMqtt(topic, buf, retained); +#else + return false; +#endif } bool publishMqtt(const char *topic, uint32_t payload, bool retained) { - #ifdef MQTT_ENABLE - char buf[11]; - snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%u", payload); - return publishMqtt(topic, buf, retained); - #else - return false; - #endif +#ifdef MQTT_ENABLE + char buf[11]; + snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%u", payload); + return publishMqtt(topic, buf, retained); +#else + return false; +#endif } // Cyclic posting of WiFi-signal-strength void Mqtt_PostWiFiRssi(void) { - #ifdef MQTT_ENABLE - static uint32_t lastMqttRssiTimestamp = 0; +#ifdef MQTT_ENABLE + static uint32_t lastMqttRssiTimestamp = 0; - if (!lastMqttRssiTimestamp || (millis() - lastMqttRssiTimestamp >= 60000)) { - lastMqttRssiTimestamp = millis(); - publishMqtt(topicWiFiRssiState, Wlan_GetRssi(), false); - } - #endif + if (!lastMqttRssiTimestamp || (millis() - lastMqttRssiTimestamp >= 60000)) { + lastMqttRssiTimestamp = millis(); + publishMqtt(topicWiFiRssiState, Wlan_GetRssi(), false); + } +#endif } /* Connects/reconnects to MQTT-Broker unless connection is not already available. Manages MQTT-subscriptions. */ bool Mqtt_Reconnect() { - #ifdef MQTT_ENABLE - static uint32_t mqttLastRetryTimestamp = 0u; - uint8_t connect = false; - uint8_t i = 0; +#ifdef MQTT_ENABLE + static uint32_t mqttLastRetryTimestamp = 0u; + uint8_t connect = false; + uint8_t i = 0; - if (!mqttLastRetryTimestamp || millis() - mqttLastRetryTimestamp >= mqttRetryInterval * 1000) { - mqttLastRetryTimestamp = millis(); - } else { - return false; - } + if (!mqttLastRetryTimestamp || millis() - mqttLastRetryTimestamp >= mqttRetryInterval * 1000) { + mqttLastRetryTimestamp = millis(); + } else { + return false; + } - while (!Mqtt_PubSubClient.connected() && i < mqttMaxRetriesPerInterval) { - i++; - Log_Printf(LOGLEVEL_NOTICE, tryConnectMqttS, gMqttServer.c_str()); + while (!Mqtt_PubSubClient.connected() && i < mqttMaxRetriesPerInterval) { + i++; + Log_Printf(LOGLEVEL_NOTICE, tryConnectMqttS, gMqttServer.c_str()); - // Try to connect to MQTT-server. If username AND password are set, they'll be used - if ((gMqttUser.length() < 1u) || (gMqttPassword.length()) < 1u) { - Log_Println(mqttWithoutPwd, LOGLEVEL_NOTICE); - if (Mqtt_PubSubClient.connect(gMqttClientId.c_str())) { - connect = true; - } - } else { - Log_Println(mqttWithPwd, LOGLEVEL_NOTICE); - if (Mqtt_PubSubClient.connect(gMqttClientId.c_str(), gMqttUser.c_str(), gMqttPassword.c_str(), topicState, 0, false, "Offline")) { - connect = true; - } + // Try to connect to MQTT-server. If username AND password are set, they'll be used + if ((gMqttUser.length() < 1u) || (gMqttPassword.length()) < 1u) { + Log_Println(mqttWithoutPwd, LOGLEVEL_NOTICE); + if (Mqtt_PubSubClient.connect(gMqttClientId.c_str())) { + connect = true; + } + } else { + Log_Println(mqttWithPwd, LOGLEVEL_NOTICE); + if (Mqtt_PubSubClient.connect(gMqttClientId.c_str(), gMqttUser.c_str(), gMqttPassword.c_str(), topicState, 0, false, "Offline")) { + connect = true; } - if (connect) { - Log_Println(mqttOk, LOGLEVEL_NOTICE); + } + if (connect) { + Log_Println(mqttOk, LOGLEVEL_NOTICE); - // Deepsleep-subscription - Mqtt_PubSubClient.subscribe(topicSleepCmnd); + // Deepsleep-subscription + Mqtt_PubSubClient.subscribe(topicSleepCmnd); - // RFID-Tag-ID-subscription - Mqtt_PubSubClient.subscribe(topicRfidCmnd); + // RFID-Tag-ID-subscription + Mqtt_PubSubClient.subscribe(topicRfidCmnd); - // Loudness-subscription - Mqtt_PubSubClient.subscribe(topicLoudnessCmnd); + // Loudness-subscription + Mqtt_PubSubClient.subscribe(topicLoudnessCmnd); - // Sleep-Timer-subscription - Mqtt_PubSubClient.subscribe(topicSleepTimerCmnd); + // Sleep-Timer-subscription + Mqtt_PubSubClient.subscribe(topicSleepTimerCmnd); - // Next/previous/stop/play-track-subscription - Mqtt_PubSubClient.subscribe(topicTrackControlCmnd); + // Next/previous/stop/play-track-subscription + Mqtt_PubSubClient.subscribe(topicTrackControlCmnd); - // Lock controls - Mqtt_PubSubClient.subscribe(topicLockControlsCmnd); + // Lock controls + Mqtt_PubSubClient.subscribe(topicLockControlsCmnd); - // Current repeat-Mode - Mqtt_PubSubClient.subscribe(topicRepeatModeCmnd); + // Current repeat-Mode + Mqtt_PubSubClient.subscribe(topicRepeatModeCmnd); - // LED-brightness - Mqtt_PubSubClient.subscribe(topicLedBrightnessCmnd); + // LED-brightness + Mqtt_PubSubClient.subscribe(topicLedBrightnessCmnd); - // Publish current state - publishMqtt(topicState, "Online", false); - publishMqtt(topicTrackState, gPlayProperties.title, false); - publishMqtt(topicCoverChangedState, "", false); - publishMqtt(topicLoudnessState, AudioPlayer_GetCurrentVolume(), false); - publishMqtt(topicSleepTimerState, System_GetSleepTimerTimeStamp(), false); - publishMqtt(topicLockControlsState, System_AreControlsLocked(), false); - publishMqtt(topicPlaymodeState, gPlayProperties.playMode, false); - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - publishMqtt(topicCurrentIPv4IP, Wlan_GetIpAddress().c_str(), false); - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + // Publish current state + publishMqtt(topicState, "Online", false); + publishMqtt(topicTrackState, gPlayProperties.title, false); + publishMqtt(topicCoverChangedState, "", false); + publishMqtt(topicLoudnessState, AudioPlayer_GetCurrentVolume(), false); + publishMqtt(topicSleepTimerState, System_GetSleepTimerTimeStamp(), false); + publishMqtt(topicLockControlsState, System_AreControlsLocked(), false); + publishMqtt(topicPlaymodeState, gPlayProperties.playMode, false); + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); + publishMqtt(topicCurrentIPv4IP, Wlan_GetIpAddress().c_str(), false); + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - char revBuf[12]; - strncpy(revBuf, softwareRevision+19, sizeof(revBuf)-1); - revBuf[sizeof(revBuf)-1] = '\0'; - publishMqtt(topicSRevisionState, revBuf, false); + char revBuf[12]; + strncpy(revBuf, softwareRevision + 19, sizeof(revBuf) - 1); + revBuf[sizeof(revBuf) - 1] = '\0'; + publishMqtt(topicSRevisionState, revBuf, false); - return Mqtt_PubSubClient.connected(); - } else { - Log_Printf(LOGLEVEL_ERROR, mqttConnFailed, Mqtt_PubSubClient.state(), i, mqttMaxRetriesPerInterval); - } + return Mqtt_PubSubClient.connected(); + } else { + Log_Printf(LOGLEVEL_ERROR, mqttConnFailed, Mqtt_PubSubClient.state(), i, mqttMaxRetriesPerInterval); } - return false; - #else - return false; - #endif + } + return false; +#else + return false; +#endif } // Is called if there's a new MQTT-message for us void Mqtt_ClientCallback(const char *topic, const byte *payload, uint32_t length) { - #ifdef MQTT_ENABLE - char *receivedString = (char*)x_calloc(length + 1u, sizeof(char)); - memcpy(receivedString, (char *) payload, length); +#ifdef MQTT_ENABLE + char *receivedString = (char *) x_calloc(length + 1u, sizeof(char)); + memcpy(receivedString, (char *) payload, length); - Log_Printf(LOGLEVEL_INFO, mqttMsgReceived, topic, receivedString); + Log_Printf(LOGLEVEL_INFO, mqttMsgReceived, topic, receivedString); - // Go to sleep? - if (strcmp_P(topic, topicSleepCmnd) == 0) { - if ((strcmp(receivedString, "OFF") == 0) || (strcmp(receivedString, "0") == 0)) { - System_RequestSleep(); - } + // Go to sleep? + if (strcmp_P(topic, topicSleepCmnd) == 0) { + if ((strcmp(receivedString, "OFF") == 0) || (strcmp(receivedString, "0") == 0)) { + System_RequestSleep(); } - // New track to play? Take RFID-ID as input - else if (strcmp_P(topic, topicRfidCmnd) == 0) { - xQueueSend(gRfidCardQueue, receivedString, 0); - } - // Loudness to change? - else if (strcmp_P(topic, topicLoudnessCmnd) == 0) { - unsigned long vol = strtoul(receivedString, NULL, 10); - AudioPlayer_VolumeToQueueSender(vol, true); + } + // New track to play? Take RFID-ID as input + else if (strcmp_P(topic, topicRfidCmnd) == 0) { + xQueueSend(gRfidCardQueue, receivedString, 0); + } + // Loudness to change? + else if (strcmp_P(topic, topicLoudnessCmnd) == 0) { + unsigned long vol = strtoul(receivedString, NULL, 10); + AudioPlayer_VolumeToQueueSender(vol, true); + } + // Modify sleep-timer? + else if (strcmp_P(topic, topicSleepTimerCmnd) == 0) { + if (gPlayProperties.playMode == NO_PLAYLIST) { // Don't allow sleep-modications if no playlist is active + Log_Println(modificatorNotallowedWhenIdle, LOGLEVEL_INFO); + publishMqtt(topicSleepState, 0, false); + System_IndicateError(); + free(receivedString); + return; } - // Modify sleep-timer? - else if (strcmp_P(topic, topicSleepTimerCmnd) == 0) { - if (gPlayProperties.playMode == NO_PLAYLIST) { // Don't allow sleep-modications if no playlist is active - Log_Println(modificatorNotallowedWhenIdle, LOGLEVEL_INFO); - publishMqtt(topicSleepState, 0, false); - System_IndicateError(); - free(receivedString); - return; + if (strcmp(receivedString, "EOP") == 0) { + gPlayProperties.sleepAfterPlaylist = true; + Log_Println(sleepTimerEOP, LOGLEVEL_NOTICE); + publishMqtt(topicSleepTimerState, "EOP", false); + Led_ResetToNightBrightness(); + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); + System_IndicateOk(); + free(receivedString); + return; + } else if (strcmp(receivedString, "EOT") == 0) { + gPlayProperties.sleepAfterCurrentTrack = true; + Log_Println(sleepTimerEOT, LOGLEVEL_NOTICE); + publishMqtt(topicSleepTimerState, "EOT", false); + Led_ResetToNightBrightness(); + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); + System_IndicateOk(); + free(receivedString); + return; + } else if (strcmp(receivedString, "EO5T") == 0) { + if ((gPlayProperties.numberOfTracks - 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 } - if (strcmp(receivedString, "EOP") == 0) { - gPlayProperties.sleepAfterPlaylist = true; - Log_Println(sleepTimerEOP, LOGLEVEL_NOTICE); - publishMqtt(topicSleepTimerState, "EOP", false); - Led_ResetToNightBrightness(); - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - System_IndicateOk(); - free(receivedString); - return; - } else if (strcmp(receivedString, "EOT") == 0) { - gPlayProperties.sleepAfterCurrentTrack = true; - Log_Println(sleepTimerEOT, LOGLEVEL_NOTICE); - publishMqtt(topicSleepTimerState, "EOT", false); - Led_ResetToNightBrightness(); - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); + Log_Println(sleepTimerEO5, LOGLEVEL_NOTICE); + publishMqtt(topicSleepTimerState, "EO5T", false); + Led_ResetToNightBrightness(); + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); + System_IndicateOk(); + free(receivedString); + return; + } else if (strcmp(receivedString, "0") == 0) { // Disable sleep after it was active previously + if (System_IsSleepTimerEnabled()) { + System_DisableSleepTimer(); + Log_Println(sleepTimerStop, LOGLEVEL_NOTICE); System_IndicateOk(); - free(receivedString); - return; - } else if (strcmp(receivedString, "EO5T") == 0) { - if ((gPlayProperties.numberOfTracks - 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_ResetToNightBrightness(); + publishMqtt(topicSleepState, 0, false); publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - System_IndicateOk(); - free(receivedString); - return; - } else if (strcmp(receivedString, "0") == 0) { // Disable sleep after it was active previously - if (System_IsSleepTimerEnabled()) { - System_DisableSleepTimer(); - Log_Println(sleepTimerStop, LOGLEVEL_NOTICE); - System_IndicateOk(); - publishMqtt(topicSleepState, 0, false); - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - gPlayProperties.sleepAfterPlaylist = false; - gPlayProperties.sleepAfterCurrentTrack = false; - gPlayProperties.playUntilTrackNumber = 0; - } else { - Log_Println(sleepTimerAlreadyStopped, LOGLEVEL_INFO); - System_IndicateError(); - } - free(receivedString); - return; + gPlayProperties.sleepAfterPlaylist = false; + gPlayProperties.sleepAfterCurrentTrack = false; + gPlayProperties.playUntilTrackNumber = 0; + } else { + Log_Println(sleepTimerAlreadyStopped, LOGLEVEL_INFO); + System_IndicateError(); } - System_SetSleepTimer((uint8_t)strtoul(receivedString, NULL, 10)); - 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 (strcmp_P(topic, topicTrackControlCmnd) == 0) { - uint8_t controlCommand = strtoul(receivedString, NULL, 10); - AudioPlayer_TrackControlToQueueSender(controlCommand); + free(receivedString); + return; } - - // Check if controls should be locked - else if (strcmp_P(topic, topicLockControlsCmnd) == 0) { - if (strcmp(receivedString, "OFF") == 0) { - System_SetLockControls(false); - Log_Println(allowButtons, LOGLEVEL_NOTICE); - publishMqtt(topicLockControlsState, "OFF", false); - System_IndicateOk(); - } else if (strcmp(receivedString, "ON") == 0) { - System_SetLockControls(true); - Log_Println(lockButtons, LOGLEVEL_NOTICE); - publishMqtt(topicLockControlsState, "ON", false); - System_IndicateOk(); - } + System_SetSleepTimer((uint8_t) strtoul(receivedString, NULL, 10)); + 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 (strcmp_P(topic, topicTrackControlCmnd) == 0) { + uint8_t controlCommand = strtoul(receivedString, NULL, 10); + AudioPlayer_TrackControlToQueueSender(controlCommand); + } + + // Check if controls should be locked + else if (strcmp_P(topic, topicLockControlsCmnd) == 0) { + if (strcmp(receivedString, "OFF") == 0) { + System_SetLockControls(false); + Log_Println(allowButtons, LOGLEVEL_NOTICE); + publishMqtt(topicLockControlsState, "OFF", false); + System_IndicateOk(); + } else if (strcmp(receivedString, "ON") == 0) { + System_SetLockControls(true); + Log_Println(lockButtons, LOGLEVEL_NOTICE); + publishMqtt(topicLockControlsState, "ON", false); + System_IndicateOk(); } - - // Check if playmode should be adjusted - else if (strcmp_P(topic, topicRepeatModeCmnd) == 0) { - uint8_t repeatMode = strtoul(receivedString, NULL, 10); - Log_Printf(LOGLEVEL_NOTICE, "Repeat: %d", repeatMode); - if (gPlayProperties.playMode != NO_PLAYLIST) { - if (gPlayProperties.playMode == NO_PLAYLIST) { - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - Log_Println(noPlaylistNotAllowedMqtt, LOGLEVEL_ERROR); - System_IndicateError(); - } else { - switch (repeatMode) { - case NO_REPEAT: - gPlayProperties.repeatCurrentTrack = false; - gPlayProperties.repeatPlaylist = false; - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - Log_Println(modeRepeatNone, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - case TRACK: - gPlayProperties.repeatCurrentTrack = true; - gPlayProperties.repeatPlaylist = false; - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - Log_Println(modeRepeatTrack, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - case PLAYLIST: - gPlayProperties.repeatCurrentTrack = false; - gPlayProperties.repeatPlaylist = true; - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - Log_Println(modeRepeatPlaylist, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - case TRACK_N_PLAYLIST: - gPlayProperties.repeatCurrentTrack = true; - gPlayProperties.repeatPlaylist = true; - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - Log_Println(modeRepeatTracknPlaylist, LOGLEVEL_INFO); - System_IndicateOk(); - break; - - default: - System_IndicateError(); - publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); - break; - } + } + + // Check if playmode should be adjusted + else if (strcmp_P(topic, topicRepeatModeCmnd) == 0) { + uint8_t repeatMode = strtoul(receivedString, NULL, 10); + Log_Printf(LOGLEVEL_NOTICE, "Repeat: %d", repeatMode); + if (gPlayProperties.playMode != NO_PLAYLIST) { + if (gPlayProperties.playMode == NO_PLAYLIST) { + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + Log_Println(noPlaylistNotAllowedMqtt, LOGLEVEL_ERROR); + System_IndicateError(); + } else { + switch (repeatMode) { + case NO_REPEAT: + gPlayProperties.repeatCurrentTrack = false; + gPlayProperties.repeatPlaylist = false; + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + Log_Println(modeRepeatNone, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + case TRACK: + gPlayProperties.repeatCurrentTrack = true; + gPlayProperties.repeatPlaylist = false; + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + Log_Println(modeRepeatTrack, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + case PLAYLIST: + gPlayProperties.repeatCurrentTrack = false; + gPlayProperties.repeatPlaylist = true; + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + Log_Println(modeRepeatPlaylist, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + case TRACK_N_PLAYLIST: + gPlayProperties.repeatCurrentTrack = true; + gPlayProperties.repeatPlaylist = true; + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + Log_Println(modeRepeatTracknPlaylist, LOGLEVEL_INFO); + System_IndicateOk(); + break; + + default: + System_IndicateError(); + publishMqtt(topicRepeatModeState, AudioPlayer_GetRepeatMode(), false); + break; } } } + } - // Check if LEDs should be dimmed - else if (strcmp_P(topic, topicLedBrightnessCmnd) == 0) { - Led_SetBrightness(strtoul(receivedString, NULL, 10)); - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - } + // Check if LEDs should be dimmed + else if (strcmp_P(topic, topicLedBrightnessCmnd) == 0) { + Led_SetBrightness(strtoul(receivedString, NULL, 10)); + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); + } - // Requested something that isn't specified? - else { - Log_Printf(LOGLEVEL_ERROR, noValidTopic, topic); - System_IndicateError(); - } + // Requested something that isn't specified? + else { + Log_Printf(LOGLEVEL_ERROR, noValidTopic, topic); + System_IndicateError(); + } - free(receivedString); - #endif + free(receivedString); +#endif } diff --git a/src/Mqtt.h b/src/Mqtt.h index 1fd64aab..f7554884 100644 --- a/src/Mqtt.h +++ b/src/Mqtt.h @@ -1,7 +1,7 @@ #pragma once #ifdef MQTT_ENABLE - #define MQTT_SOCKET_TIMEOUT 1 // https://github.com/knolleary/pubsubclient/issues/403 + #define MQTT_SOCKET_TIMEOUT 1 // https://github.com/knolleary/pubsubclient/issues/403 #include #endif // MQTT-configuration diff --git a/src/Port.cpp b/src/Port.cpp index 1d962569..2536bdf7 100644 --- a/src/Port.cpp +++ b/src/Port.cpp @@ -1,9 +1,12 @@ #include -#include #include "settings.h" + #include "Port.h" + #include "Log.h" +#include + // Infos: // PCA9555 has 16 channels that are subdivided into 2 ports with 8 channels each. // Every channels is represented by a bit. @@ -14,41 +17,41 @@ // 115 => port 1 channel/bit 7 #ifdef PORT_EXPANDER_ENABLE - extern TwoWire i2cBusTwo; +extern TwoWire i2cBusTwo; - uint8_t Port_ExpanderPortsInputChannelStatus[2]; - static uint8_t Port_ExpanderPortsOutputChannelStatus[2] = {255, 255}; // Stores current configuration of output-channels locally - void Port_ExpanderHandler(void); - uint8_t Port_ChannelToBit(const uint8_t _channel); - void Port_WriteInitMaskForOutputChannels(void); - void Port_Test(void); +uint8_t Port_ExpanderPortsInputChannelStatus[2]; +static uint8_t Port_ExpanderPortsOutputChannelStatus[2] = {255, 255}; // Stores current configuration of output-channels locally +void Port_ExpanderHandler(void); +uint8_t Port_ChannelToBit(const uint8_t _channel); +void Port_WriteInitMaskForOutputChannels(void); +void Port_Test(void); #if (PE_INTERRUPT_PIN >= 0 && PE_INTERRUPT_PIN <= MAX_GPIO) #define PE_INTERRUPT_PIN_ENABLE - void IRAM_ATTR PORT_ExpanderISR(void); - bool Port_AllowReadFromPortExpander = false; - bool Port_AllowInitReadFromPortExpander = true; +void IRAM_ATTR PORT_ExpanderISR(void); +bool Port_AllowReadFromPortExpander = false; +bool Port_AllowInitReadFromPortExpander = true; #endif #endif void Port_Init(void) { - #ifdef PORT_EXPANDER_ENABLE - Port_Test(); - Port_WriteInitMaskForOutputChannels(); - Port_ExpanderHandler(); - #endif +#ifdef PORT_EXPANDER_ENABLE + Port_Test(); + Port_WriteInitMaskForOutputChannels(); + Port_ExpanderHandler(); +#endif - #ifdef PE_INTERRUPT_PIN_ENABLE - pinMode(PE_INTERRUPT_PIN, INPUT_PULLUP); - attachInterrupt(PE_INTERRUPT_PIN, PORT_ExpanderISR, FALLING); - Log_Println(portExpanderInterruptEnabled, LOGLEVEL_NOTICE); - #endif +#ifdef PE_INTERRUPT_PIN_ENABLE + pinMode(PE_INTERRUPT_PIN, INPUT_PULLUP); + attachInterrupt(PE_INTERRUPT_PIN, PORT_ExpanderISR, FALLING); + Log_Println(portExpanderInterruptEnabled, LOGLEVEL_NOTICE); +#endif } void Port_Cyclic(void) { - #ifdef PORT_EXPANDER_ENABLE - Port_ExpanderHandler(); - #endif +#ifdef PORT_EXPANDER_ENABLE + Port_ExpanderHandler(); +#endif } // Wrapper: reads from GPIOs (via digitalRead()) or from port-expander (if enabled) @@ -58,14 +61,14 @@ bool Port_Read(const uint8_t _channel) { case 0 ... MAX_GPIO: // GPIO return digitalRead(_channel); - #ifdef PORT_EXPANDER_ENABLE - case 100 ... 107: // Port-expander (port 0) - return (Port_ExpanderPortsInputChannelStatus[0] & (1 << (_channel - 100))); // Remove offset 100 (return false if pressed) +#ifdef PORT_EXPANDER_ENABLE + case 100 ... 107: // Port-expander (port 0) + return (Port_ExpanderPortsInputChannelStatus[0] & (1 << (_channel - 100))); // Remove offset 100 (return false if pressed) - case 108 ... 115: // Port-expander (port 1) - return (Port_ExpanderPortsInputChannelStatus[1] & (1 << (_channel - 108))); // Remove offset 100 + 8 (return false if pressed) + case 108 ... 115: // Port-expander (port 1) + return (Port_ExpanderPortsInputChannelStatus[1] & (1 << (_channel - 108))); // Remove offset 100 + 8 (return false if pressed) - #endif +#endif default: // Everything else (doesn't make sense at all) isn't supposed to be pressed return true; @@ -75,25 +78,25 @@ bool Port_Read(const uint8_t _channel) { // Configures OUTPUT-mode for GPIOs (non port-expander) // Output-mode for port-channels is done via Port_WriteInitMaskForOutputChannels() void Port_Write(const uint8_t _channel, const bool _newState, const bool _initGpio) { - #ifdef GPIO_PA_EN - if (_channel == GPIO_PA_EN) { - if (_newState) { - Log_Println(paOn, LOGLEVEL_NOTICE); - } else { - Log_Println(paOff, LOGLEVEL_NOTICE); - } +#ifdef GPIO_PA_EN + if (_channel == GPIO_PA_EN) { + if (_newState) { + Log_Println(paOn, LOGLEVEL_NOTICE); + } else { + Log_Println(paOff, LOGLEVEL_NOTICE); } - #endif + } +#endif - #ifdef GPIO_HP_EN - if (_channel == GPIO_HP_EN) { - if (_newState) { - Log_Println(hpOn, LOGLEVEL_NOTICE); - } else { - Log_Println(hpOff, LOGLEVEL_NOTICE); - } +#ifdef GPIO_HP_EN + if (_channel == GPIO_HP_EN) { + if (_newState) { + Log_Println(hpOn, LOGLEVEL_NOTICE); + } else { + Log_Println(hpOff, LOGLEVEL_NOTICE); } - #endif + } +#endif // Make init only for GPIO but not for PE (because PE is already done earlier) if (_initGpio) { @@ -108,31 +111,31 @@ void Port_Write(const uint8_t _channel, const bool _newState, const bool _initGp break; } - #ifdef PORT_EXPANDER_ENABLE - case 100 ... 115: { - uint8_t portOffset = 0; - if (_channel >= 108 && _channel <= 115) { - portOffset = 1; - } - - uint8_t oldPortBitmask = Port_ExpanderPortsOutputChannelStatus[portOffset]; - uint8_t newPortBitmask; - - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x02); // Pointer to output configuration-register - if (_newState) { - newPortBitmask = (oldPortBitmask | (1 << Port_ChannelToBit(_channel))); - Port_ExpanderPortsOutputChannelStatus[portOffset] = newPortBitmask; // Write back new status - } else { - newPortBitmask = (oldPortBitmask & ~(1 << Port_ChannelToBit(_channel))); - Port_ExpanderPortsOutputChannelStatus[portOffset] = newPortBitmask; // Write back new status - } - i2cBusTwo.write(Port_ExpanderPortsOutputChannelStatus[0]); - i2cBusTwo.write(Port_ExpanderPortsOutputChannelStatus[1]); - i2cBusTwo.endTransmission(); - break; +#ifdef PORT_EXPANDER_ENABLE + case 100 ... 115: { + uint8_t portOffset = 0; + if (_channel >= 108 && _channel <= 115) { + portOffset = 1; + } + + uint8_t oldPortBitmask = Port_ExpanderPortsOutputChannelStatus[portOffset]; + uint8_t newPortBitmask; + + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x02); // Pointer to output configuration-register + if (_newState) { + newPortBitmask = (oldPortBitmask | (1 << Port_ChannelToBit(_channel))); + Port_ExpanderPortsOutputChannelStatus[portOffset] = newPortBitmask; // Write back new status + } else { + newPortBitmask = (oldPortBitmask & ~(1 << Port_ChannelToBit(_channel))); + Port_ExpanderPortsOutputChannelStatus[portOffset] = newPortBitmask; // Write back new status } - #endif + i2cBusTwo.write(Port_ExpanderPortsOutputChannelStatus[0]); + i2cBusTwo.write(Port_ExpanderPortsOutputChannelStatus[1]); + i2cBusTwo.endTransmission(); + break; + } +#endif default: { break; @@ -141,256 +144,256 @@ void Port_Write(const uint8_t _channel, const bool _newState, const bool _initGp } #ifdef PORT_EXPANDER_ENABLE - // Translates digitalWrite-style "GPIO" to bit - uint8_t Port_ChannelToBit(const uint8_t _channel) { - switch (_channel) { - case 100: - case 108: - return 0; - break; - case 101: - case 109: - return 1; - break; - case 102: - case 110: - return 2; - break; - case 103: - case 111: - return 3; - break; - case 104: - case 112: - return 4; - break; - case 105: - case 113: - return 5; - break; - case 106: - case 114: - return 6; - break; - case 107: - case 115: - return 7; - break; - - default: - return 255; // not valid! - } - } +// Translates digitalWrite-style "GPIO" to bit +uint8_t Port_ChannelToBit(const uint8_t _channel) { + switch (_channel) { + case 100: + case 108: + return 0; + break; + case 101: + case 109: + return 1; + break; + case 102: + case 110: + return 2; + break; + case 103: + case 111: + return 3; + break; + case 104: + case 112: + return 4; + break; + case 105: + case 113: + return 5; + break; + case 106: + case 114: + return 6; + break; + case 107: + case 115: + return 7; + break; - // Writes initial port-configuration (I/O) for port-expander PCA9555 - // If no output-channel is necessary, nothing has to be configured as all channels are in input-mode as per default (255) - // So every bit representing an output-channel needs to be set to 0. - void Port_WriteInitMaskForOutputChannels(void) { - const uint8_t portBaseValueBitMask = 255; - const uint8_t portsToWrite = 2; - uint8_t OutputBitMaskInOutAsPerPort[portsToWrite] = { portBaseValueBitMask, portBaseValueBitMask }; // 255 => all channels set to input; [0]: port0, [1]: port1 - uint8_t OutputBitMaskLowHighAsPerPort[portsToWrite] = { 0x00, 0x00}; // Bit configured as 0 for an output-channels means: logic LOW - - #ifdef GPIO_PA_EN // Set as output to enable/disable amp for loudspeaker - if (GPIO_PA_EN >= 100 && GPIO_PA_EN <= 107) { - // Bits of channels to be configured as input are 1 by default. - // So in order to change I/O-direction to output we need to set those bits to 0. - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); - } else if (GPIO_PA_EN >= 108 && GPIO_PA_EN <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); - } - #endif + default: + return 255; // not valid! + } +} - #ifdef GPIO_HP_EN // Set as output to enable/disable amp for headphones - if (GPIO_HP_EN >= 100 && GPIO_HP_EN <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); - } else if (GPIO_HP_EN >= 108 && GPIO_HP_EN <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); - } - #endif +// Writes initial port-configuration (I/O) for port-expander PCA9555 +// If no output-channel is necessary, nothing has to be configured as all channels are in input-mode as per default (255) +// So every bit representing an output-channel needs to be set to 0. +void Port_WriteInitMaskForOutputChannels(void) { + const uint8_t portBaseValueBitMask = 255; + const uint8_t portsToWrite = 2; + uint8_t OutputBitMaskInOutAsPerPort[portsToWrite] = {portBaseValueBitMask, portBaseValueBitMask}; // 255 => all channels set to input; [0]: port0, [1]: port1 + uint8_t OutputBitMaskLowHighAsPerPort[portsToWrite] = {0x00, 0x00}; // Bit configured as 0 for an output-channels means: logic LOW + + #ifdef GPIO_PA_EN // Set as output to enable/disable amp for loudspeaker + if (GPIO_PA_EN >= 100 && GPIO_PA_EN <= 107) { + // Bits of channels to be configured as input are 1 by default. + // So in order to change I/O-direction to output we need to set those bits to 0. + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); + } else if (GPIO_PA_EN >= 108 && GPIO_PA_EN <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); + } + #endif - #ifdef POWER // Set as output to trigger mosfet/power-pin for powering peripherals. Hint: logic is inverted if INVERT_POWER is enabled. - if (POWER >= 100 && POWER <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(POWER)); - } else if (POWER >= 108 && POWER <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(POWER)); - } - #endif + #ifdef GPIO_HP_EN // Set as output to enable/disable amp for headphones + if (GPIO_HP_EN >= 100 && GPIO_HP_EN <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); + } else if (GPIO_HP_EN >= 108 && GPIO_HP_EN <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); + } + #endif - #ifdef BUTTONS_LED - if (BUTTONS_LED >= 100 && BUTTONS_LED <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); - } else if (BUTTONS_LED >= 108 && BUTTONS_LED <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); - } - #endif + #ifdef POWER // Set as output to trigger mosfet/power-pin for powering peripherals. Hint: logic is inverted if INVERT_POWER is enabled. + if (POWER >= 100 && POWER <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(POWER)); + } else if (POWER >= 108 && POWER <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(POWER)); + } + #endif - // Only change port-config if necessary (at least bitmask changed from base-default for one port) - if ((OutputBitMaskInOutAsPerPort[0] != portBaseValueBitMask) || (OutputBitMaskInOutAsPerPort[1] != portBaseValueBitMask)) { - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x06); // Pointer to configuration of input/output - for (uint8_t i=0; i= 100 && BUTTONS_LED <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); + } else if (BUTTONS_LED >= 108 && BUTTONS_LED <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); + } + #endif - // Write low/high-config to all output-channels. Channels that are configured as input are silently/automatically ignored by PCA9555 - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x02); // Pointer to configuration of output-channels (high/low) - i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[0]); // port0 - i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[1]); // port1 - i2cBusTwo.endTransmission(); + // Only change port-config if necessary (at least bitmask changed from base-default for one port) + if ((OutputBitMaskInOutAsPerPort[0] != portBaseValueBitMask) || (OutputBitMaskInOutAsPerPort[1] != portBaseValueBitMask)) { + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x06); // Pointer to configuration of input/output + for (uint8_t i = 0; i < portsToWrite; i++) { + i2cBusTwo.write(OutputBitMaskInOutAsPerPort[i]); + // Serial.printf("Register %u - Mask: %u\n", 0x06+i, OutputBitMaskInOutAsPerPort[i]); } + i2cBusTwo.endTransmission(); + + // Write low/high-config to all output-channels. Channels that are configured as input are silently/automatically ignored by PCA9555 + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x02); // Pointer to configuration of output-channels (high/low) + i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[0]); // port0 + i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[1]); // port1 + i2cBusTwo.endTransmission(); } +} - // Some channels are configured as output before shutdown in order to avoid unwanted interrupts while ESP32 sleeps - void Port_MakeSomeChannelsOutputForShutdown(void) { - const uint8_t portBaseValueBitMask = 255; - const uint8_t portsToWrite = 2; - uint8_t OutputBitMaskInOutAsPerPort[portsToWrite] = { portBaseValueBitMask, portBaseValueBitMask }; // 255 => all channels set to input; [0]: port0, [1]: port1 - uint8_t OutputBitMaskLowHighAsPerPort[portsToWrite] = { 0x00, 0x00}; - - #ifdef HP_DETECT // https://forum.espuino.de/t/lolin-d32-pro-mit-sd-mmc-pn5180-max-fuenf-buttons-und-port-expander-smd/638/33 - if (HP_DETECT >= 100 && HP_DETECT <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(HP_DETECT)); - } else if (HP_DETECT >= 108 && HP_DETECT <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(HP_DETECT)); - } - #endif +// Some channels are configured as output before shutdown in order to avoid unwanted interrupts while ESP32 sleeps +void Port_MakeSomeChannelsOutputForShutdown(void) { + const uint8_t portBaseValueBitMask = 255; + const uint8_t portsToWrite = 2; + uint8_t OutputBitMaskInOutAsPerPort[portsToWrite] = {portBaseValueBitMask, portBaseValueBitMask}; // 255 => all channels set to input; [0]: port0, [1]: port1 + uint8_t OutputBitMaskLowHighAsPerPort[portsToWrite] = {0x00, 0x00}; + + #ifdef HP_DETECT // https://forum.espuino.de/t/lolin-d32-pro-mit-sd-mmc-pn5180-max-fuenf-buttons-und-port-expander-smd/638/33 + if (HP_DETECT >= 100 && HP_DETECT <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(HP_DETECT)); + } else if (HP_DETECT >= 108 && HP_DETECT <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(HP_DETECT)); + } + #endif - // There's no possibility to get current I/O-status from PCA9555. So we just re-set it again for OUTPUT-pins. - #ifdef GPIO_PA_EN - if (GPIO_PA_EN >= 100 && GPIO_PA_EN <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); - } else if (GPIO_PA_EN >= 108 && GPIO_PA_EN <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); - } - #endif + // There's no possibility to get current I/O-status from PCA9555. So we just re-set it again for OUTPUT-pins. + #ifdef GPIO_PA_EN + if (GPIO_PA_EN >= 100 && GPIO_PA_EN <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); + } else if (GPIO_PA_EN >= 108 && GPIO_PA_EN <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_PA_EN)); + } + #endif - #ifdef GPIO_HP_EN - if (GPIO_HP_EN >= 100 && GPIO_HP_EN <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); - } else if (GPIO_HP_EN >= 108 && GPIO_HP_EN <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); - } - #endif + #ifdef GPIO_HP_EN + if (GPIO_HP_EN >= 100 && GPIO_HP_EN <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); + } else if (GPIO_HP_EN >= 108 && GPIO_HP_EN <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(GPIO_HP_EN)); + } + #endif - #ifdef POWER // Set as output to trigger mosfet/power-pin for powering peripherals. Hint: logic is inverted if INVERT_POWER is enabled. - if (POWER >= 100 && POWER <= 107) { - #ifdef INVERT_POWER - OutputBitMaskLowHighAsPerPort[0] |= (1 << Port_ChannelToBit(POWER)); - #else - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(POWER)); - #endif - } else if (POWER >= 108 && POWER <= 115) { - #ifdef INVERT_POWER - OutputBitMaskLowHighAsPerPort[1] |= (1 << Port_ChannelToBit(POWER)); - #else - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(POWER)); - #endif - } + #ifdef POWER // Set as output to trigger mosfet/power-pin for powering peripherals. Hint: logic is inverted if INVERT_POWER is enabled. + if (POWER >= 100 && POWER <= 107) { + #ifdef INVERT_POWER + OutputBitMaskLowHighAsPerPort[0] |= (1 << Port_ChannelToBit(POWER)); + #else + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(POWER)); #endif - - #ifdef BUTTONS_LED - if (BUTTONS_LED >= 100 && BUTTONS_LED <= 107) { - OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); - } else if (BUTTONS_LED >= 108 && BUTTONS_LED <= 115) { - OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); - } + } else if (POWER >= 108 && POWER <= 115) { + #ifdef INVERT_POWER + OutputBitMaskLowHighAsPerPort[1] |= (1 << Port_ChannelToBit(POWER)); + #else + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(POWER)); #endif + } + #endif - // Only change port-config if necessary (at least bitmask changed from base-default for one port) - if ((OutputBitMaskInOutAsPerPort[0] != portBaseValueBitMask) || (OutputBitMaskInOutAsPerPort[1] != portBaseValueBitMask)) { - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x06); // Pointer to configuration of input/output - for (uint8_t i=0; i= 100 && BUTTONS_LED <= 107) { + OutputBitMaskInOutAsPerPort[0] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); + } else if (BUTTONS_LED >= 108 && BUTTONS_LED <= 115) { + OutputBitMaskInOutAsPerPort[1] &= ~(1 << Port_ChannelToBit(BUTTONS_LED)); + } + #endif - // Write low/high-config to all output-channels. Channels that are configured as input are silently/automatically ignored by PCA9555 - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x02); // Pointer to configuration of output-channels (high/low) - i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[0]); // port0 - i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[1]); // port1 - i2cBusTwo.endTransmission(); + // Only change port-config if necessary (at least bitmask changed from base-default for one port) + if ((OutputBitMaskInOutAsPerPort[0] != portBaseValueBitMask) || (OutputBitMaskInOutAsPerPort[1] != portBaseValueBitMask)) { + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x06); // Pointer to configuration of input/output + for (uint8_t i = 0; i < portsToWrite; i++) { + i2cBusTwo.write(OutputBitMaskInOutAsPerPort[i]); } + i2cBusTwo.endTransmission(); + + // Write low/high-config to all output-channels. Channels that are configured as input are silently/automatically ignored by PCA9555 + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x02); // Pointer to configuration of output-channels (high/low) + i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[0]); // port0 + i2cBusTwo.write(OutputBitMaskLowHighAsPerPort[1]); // port1 + i2cBusTwo.endTransmission(); } +} - // Reads input-registers from port-expander and writes output into global cache-array - // Datasheet: https://www.nxp.com/docs/en/data-sheet/PCA9555.pdf - void Port_ExpanderHandler(void) { - static bool verifyChangeOfInputRegister[2] = {false, false}; // Used to debounce once in case of register-change - static uint8_t inputRegisterBuffer[2]; - - // If interrupt-handling is active, only read port-expander's registers if interrupt was fired - #ifdef PE_INTERRUPT_PIN_ENABLE - if (!Port_AllowReadFromPortExpander && !Port_AllowInitReadFromPortExpander && !verifyChangeOfInputRegister[0] && !verifyChangeOfInputRegister[1]) { - return; - } else if (Port_AllowInitReadFromPortExpander) { - Port_AllowInitReadFromPortExpander = false; - } else if (Port_AllowReadFromPortExpander || Port_AllowInitReadFromPortExpander) { - Port_AllowReadFromPortExpander = false; - } - #endif +// Reads input-registers from port-expander and writes output into global cache-array +// Datasheet: https://www.nxp.com/docs/en/data-sheet/PCA9555.pdf +void Port_ExpanderHandler(void) { + static bool verifyChangeOfInputRegister[2] = {false, false}; // Used to debounce once in case of register-change + static uint8_t inputRegisterBuffer[2]; - for (uint8_t i = 0; i < 2; i++) { - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x00 + i); // Pointer to input-register... - uint8_t error = i2cBusTwo.endTransmission(); - if (error != 0) { - Log_Printf(LOGLEVEL_ERROR, "Error in endTransmission(): %d", error); - return; - } - i2cBusTwo.requestFrom(expanderI2cAddress, 1u); // ...and read its byte - - if (i2cBusTwo.available()) { - inputRegisterBuffer[i] = i2cBusTwo.read(); // Cache current readout - // Check if input-register changed. If so, don't use the value immediately - // but wait another cycle instead (=> rudimentary debounce). - // Added because there've been "ghost"-events occasionally with Arduino2 (https://forum.espuino.de/t/aktueller-stand-esp32-arduino-2/1389/55) - if (inputRegisterBuffer[i] != Port_ExpanderPortsInputChannelStatus[i] && millis() >= 10000 && !verifyChangeOfInputRegister[i]) { - verifyChangeOfInputRegister[i] = true; - //Serial.println("Verify set!"); - } else { - verifyChangeOfInputRegister[i] = false; - Port_ExpanderPortsInputChannelStatus[i] = inputRegisterBuffer[i]; - } - //Serial.printf("%u Debug: PE-Port: %u Status: %u\n", millis(), i, Port_ExpanderPortsInputChannelStatus[i]); - } - } + // If interrupt-handling is active, only read port-expander's registers if interrupt was fired + #ifdef PE_INTERRUPT_PIN_ENABLE + if (!Port_AllowReadFromPortExpander && !Port_AllowInitReadFromPortExpander && !verifyChangeOfInputRegister[0] && !verifyChangeOfInputRegister[1]) { + return; + } else if (Port_AllowInitReadFromPortExpander) { + Port_AllowInitReadFromPortExpander = false; + } else if (Port_AllowReadFromPortExpander || Port_AllowInitReadFromPortExpander) { + Port_AllowReadFromPortExpander = false; } + #endif - // Make sure ports are read finally at shutdown in order to clear any active IRQs that could cause re-wakeup immediately - void Port_Exit(void) { - Port_MakeSomeChannelsOutputForShutdown(); - for (uint8_t i = 0; i < 2; i++) { - i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x00 + i); // Pointer to input-register... - i2cBusTwo.endTransmission(); - i2cBusTwo.requestFrom(expanderI2cAddress, 1u); // ...and read its byte - - if (i2cBusTwo.available()) { - Port_ExpanderPortsInputChannelStatus[i] = i2cBusTwo.read(); + for (uint8_t i = 0; i < 2; i++) { + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x00 + i); // Pointer to input-register... + uint8_t error = i2cBusTwo.endTransmission(); + if (error != 0) { + Log_Printf(LOGLEVEL_ERROR, "Error in endTransmission(): %d", error); + return; + } + i2cBusTwo.requestFrom(expanderI2cAddress, 1u); // ...and read its byte + + if (i2cBusTwo.available()) { + inputRegisterBuffer[i] = i2cBusTwo.read(); // Cache current readout + // Check if input-register changed. If so, don't use the value immediately + // but wait another cycle instead (=> rudimentary debounce). + // Added because there've been "ghost"-events occasionally with Arduino2 (https://forum.espuino.de/t/aktueller-stand-esp32-arduino-2/1389/55) + if (inputRegisterBuffer[i] != Port_ExpanderPortsInputChannelStatus[i] && millis() >= 10000 && !verifyChangeOfInputRegister[i]) { + verifyChangeOfInputRegister[i] = true; + // Serial.println("Verify set!"); + } else { + verifyChangeOfInputRegister[i] = false; + Port_ExpanderPortsInputChannelStatus[i] = inputRegisterBuffer[i]; } + // Serial.printf("%u Debug: PE-Port: %u Status: %u\n", millis(), i, Port_ExpanderPortsInputChannelStatus[i]); } } +} - // Tests if port-expander can be detected at address configured - void Port_Test(void) { +// Make sure ports are read finally at shutdown in order to clear any active IRQs that could cause re-wakeup immediately +void Port_Exit(void) { + Port_MakeSomeChannelsOutputForShutdown(); + for (uint8_t i = 0; i < 2; i++) { i2cBusTwo.beginTransmission(expanderI2cAddress); - i2cBusTwo.write(0x02); - if (!i2cBusTwo.endTransmission()) { - Log_Println(portExpanderFound, LOGLEVEL_NOTICE); - } else { - Log_Println(portExpanderNotFound, LOGLEVEL_ERROR); + i2cBusTwo.write(0x00 + i); // Pointer to input-register... + i2cBusTwo.endTransmission(); + i2cBusTwo.requestFrom(expanderI2cAddress, 1u); // ...and read its byte + + if (i2cBusTwo.available()) { + Port_ExpanderPortsInputChannelStatus[i] = i2cBusTwo.read(); } } +} + +// Tests if port-expander can be detected at address configured +void Port_Test(void) { + i2cBusTwo.beginTransmission(expanderI2cAddress); + i2cBusTwo.write(0x02); + if (!i2cBusTwo.endTransmission()) { + Log_Println(portExpanderFound, LOGLEVEL_NOTICE); + } else { + Log_Println(portExpanderNotFound, LOGLEVEL_ERROR); + } +} #ifdef PE_INTERRUPT_PIN_ENABLE - void IRAM_ATTR PORT_ExpanderISR(void) { - Port_AllowReadFromPortExpander = true; - } +void IRAM_ATTR PORT_ExpanderISR(void) { + Port_AllowReadFromPortExpander = true; +} #endif #endif diff --git a/src/Power.cpp b/src/Power.cpp index 1b54a7e9..c3590183 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -1,29 +1,29 @@ #include #include "settings.h" -#include "Power.h" -#include "Port.h" +#include "Power.h" +#include "Port.h" void Power_Init(void) { - #if (POWER >= 0 && POWER <= MAX_GPIO) - pinMode(POWER, OUTPUT); // Only necessary for GPIO. For port-expander it's done (previously) via Port_init() - #endif +#if (POWER >= 0 && POWER <= MAX_GPIO) + pinMode(POWER, OUTPUT); // Only necessary for GPIO. For port-expander it's done (previously) via Port_init() +#endif } // Switch on peripherals. Please note: meaning of POWER_ON is HIGH per default. But is LOW in case of INVERT_POWER is enabled. void Power_PeripheralOn(void) { Port_Write(POWER, POWER_ON, false); - #ifdef BUTTONS_LED - Port_Write(BUTTONS_LED, HIGH, false); - #endif - delay(50); // Give peripherals some time to settle down +#ifdef BUTTONS_LED + Port_Write(BUTTONS_LED, HIGH, false); +#endif + delay(50); // Give peripherals some time to settle down } // Switch off peripherals. Please note: meaning of POWER_OFF is LOW per default. But is HIGH in case of INVERT_POWER is enabled. void Power_PeripheralOff(void) { Port_Write(POWER, POWER_OFF, false); - #ifdef BUTTONS_LED - Port_Write(BUTTONS_LED, LOW, false); - #endif +#ifdef BUTTONS_LED + Port_Write(BUTTONS_LED, LOW, false); +#endif } diff --git a/src/Power.h b/src/Power.h index b00010e9..06053d38 100644 --- a/src/Power.h +++ b/src/Power.h @@ -1,10 +1,10 @@ #pragma once #ifdef INVERT_POWER - #define POWER_ON LOW + #define POWER_ON LOW #define POWER_OFF HIGH #else - #define POWER_ON HIGH + #define POWER_ON HIGH #define POWER_OFF LOW #endif diff --git a/src/Queues.cpp b/src/Queues.cpp index 0610f481..85991199 100644 --- a/src/Queues.cpp +++ b/src/Queues.cpp @@ -1,5 +1,6 @@ #include #include "settings.h" + #include "Log.h" #include "Rfid.h" diff --git a/src/Rfid.h b/src/Rfid.h index eb1df942..f43bc56c 100644 --- a/src/Rfid.h +++ b/src/Rfid.h @@ -6,13 +6,13 @@ constexpr uint8_t cardIdStringSize = (cardIdSize * 3u) + 1u; extern char gCurrentRfidTagId[cardIdStringSize]; #ifndef PAUSE_WHEN_RFID_REMOVED - #ifdef DONT_ACCEPT_SAME_RFID_TWICE // ignore feature silently if PAUSE_WHEN_RFID_REMOVED is active + #ifdef DONT_ACCEPT_SAME_RFID_TWICE // ignore feature silently if PAUSE_WHEN_RFID_REMOVED is active #define DONT_ACCEPT_SAME_RFID_TWICE_ENABLE #endif #endif #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE - void Rfid_ResetOldRfid(void); +void Rfid_ResetOldRfid(void); #endif void Rfid_Init(void); diff --git a/src/RfidCommon.cpp b/src/RfidCommon.cpp index c0abc479..0cf9e473 100644 --- a/src/RfidCommon.cpp +++ b/src/RfidCommon.cpp @@ -1,6 +1,6 @@ #include #include "settings.h" -#include "Rfid.h" + #include "AudioPlayer.h" #include "Cmd.h" #include "Common.h" @@ -8,122 +8,122 @@ #include "MemX.h" #include "Mqtt.h" #include "Queues.h" +#include "Rfid.h" #include "System.h" #include "Web.h" unsigned long Rfid_LastRfidCheckTimestamp = 0; char gCurrentRfidTagId[cardIdStringSize] = ""; // No crap here as otherwise it could be shown in GUI #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE - char gOldRfidTagId[cardIdStringSize] = "X"; // Init with crap +char gOldRfidTagId[cardIdStringSize] = "X"; // Init with crap #endif // check if we have RFID-reader enabled -#if defined (RFID_READER_TYPE_MFRC522_SPI) || defined (RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_PN5180) +#if defined(RFID_READER_TYPE_MFRC522_SPI) || defined(RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_PN5180) #define RFID_READER_ENABLED 1 #endif // Tries to lookup RFID-tag-string in NVS and extracts parameter from it if found void Rfid_PreferenceLookupHandler(void) { - #if defined (RFID_READER_ENABLED) - BaseType_t rfidStatus; - char rfidTagId[cardIdStringSize]; - char _file[255]; - uint32_t _lastPlayPos = 0; - uint16_t _trackLastPlayed = 0; - uint32_t _playMode = 1; +#if defined(RFID_READER_ENABLED) + BaseType_t rfidStatus; + char rfidTagId[cardIdStringSize]; + char _file[255]; + uint32_t _lastPlayPos = 0; + uint16_t _trackLastPlayed = 0; + uint32_t _playMode = 1; - rfidStatus = xQueueReceive(gRfidCardQueue, &rfidTagId, 0); - if (rfidStatus == pdPASS) { - System_UpdateActivityTimer(); - strncpy(gCurrentRfidTagId, rfidTagId, cardIdStringSize-1); - Log_Printf(LOGLEVEL_INFO, "%s: %s", rfidTagReceived, gCurrentRfidTagId); - Web_SendWebsocketData(0, 10); // Push new rfidTagId to all websocket-clients - String s = "-1"; - if (gPrefsRfid.isKey(gCurrentRfidTagId)) { - s = gPrefsRfid.getString(gCurrentRfidTagId, "-1"); // Try to lookup rfidId in NVS - } - if (!s.compareTo("-1")) { - Log_Println(rfidTagUnknownInNvs, LOGLEVEL_ERROR); - System_IndicateError(); - #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE - strncpy(gOldRfidTagId, gCurrentRfidTagId, cardIdStringSize-1); // Even if not found in NVS: accept it as card last applied - #endif - // allow to escape from bluetooth mode with an unknown card, switch back to normal mode - System_SetOperationMode(OPMODE_NORMAL); - return; - } + rfidStatus = xQueueReceive(gRfidCardQueue, &rfidTagId, 0); + if (rfidStatus == pdPASS) { + System_UpdateActivityTimer(); + strncpy(gCurrentRfidTagId, rfidTagId, cardIdStringSize - 1); + Log_Printf(LOGLEVEL_INFO, "%s: %s", rfidTagReceived, gCurrentRfidTagId); + Web_SendWebsocketData(0, 10); // Push new rfidTagId to all websocket-clients + String s = "-1"; + if (gPrefsRfid.isKey(gCurrentRfidTagId)) { + s = gPrefsRfid.getString(gCurrentRfidTagId, "-1"); // Try to lookup rfidId in NVS + } + if (!s.compareTo("-1")) { + Log_Println(rfidTagUnknownInNvs, LOGLEVEL_ERROR); + System_IndicateError(); + #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE + strncpy(gOldRfidTagId, gCurrentRfidTagId, cardIdStringSize - 1); // Even if not found in NVS: accept it as card last applied + #endif + // allow to escape from bluetooth mode with an unknown card, switch back to normal mode + System_SetOperationMode(OPMODE_NORMAL); + return; + } - char *token; - uint8_t i = 1; - token = strtok((char *)s.c_str(), stringDelimiter); - while (token != NULL) { // Try to extract data from string after lookup - if (i == 1) { - strncpy(_file, token, sizeof(_file) / sizeof(_file[0])); - } else if (i == 2) { - _lastPlayPos = strtoul(token, NULL, 10); - } else if (i == 3) { - _playMode = strtoul(token, NULL, 10); - } else if (i == 4) { - _trackLastPlayed = strtoul(token, NULL, 10); - } - i++; - token = strtok(NULL, stringDelimiter); + char *token; + uint8_t i = 1; + token = strtok((char *) s.c_str(), stringDelimiter); + while (token != NULL) { // Try to extract data from string after lookup + if (i == 1) { + strncpy(_file, token, sizeof(_file) / sizeof(_file[0])); + } else if (i == 2) { + _lastPlayPos = strtoul(token, NULL, 10); + } else if (i == 3) { + _playMode = strtoul(token, NULL, 10); + } else if (i == 4) { + _trackLastPlayed = strtoul(token, NULL, 10); } + i++; + token = strtok(NULL, stringDelimiter); + } - if (i != 5) { - Log_Println(errorOccuredNvs, LOGLEVEL_ERROR); - System_IndicateError(); + if (i != 5) { + Log_Println(errorOccuredNvs, LOGLEVEL_ERROR); + System_IndicateError(); + } else { + // Only pass file to queue if strtok revealed 3 items + if (_playMode >= 100) { + // Modification-cards can change some settings (e.g. introducing track-looping or sleep after track/playlist). + Cmd_Action(_playMode); } else { - // Only pass file to queue if strtok revealed 3 items - if (_playMode >= 100) { - // Modification-cards can change some settings (e.g. introducing track-looping or sleep after track/playlist). - Cmd_Action(_playMode); + #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE + if (strncmp(gCurrentRfidTagId, gOldRfidTagId, 12) == 0) { + Log_Printf(LOGLEVEL_ERROR, dontAccepctSameRfid, gCurrentRfidTagId); + // System_IndicateError(); // Enable to have shown error @neopixel every time + return; } else { - #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE - if (strncmp(gCurrentRfidTagId, gOldRfidTagId, 12) == 0) { - Log_Printf(LOGLEVEL_ERROR, dontAccepctSameRfid, gCurrentRfidTagId); - //System_IndicateError(); // Enable to have shown error @neopixel every time - return; - } else { - strncpy(gOldRfidTagId, gCurrentRfidTagId, 12); - } - #endif - #ifdef MQTT_ENABLE - publishMqtt(topicRfidState, gCurrentRfidTagId, false); - #endif - - #ifdef BLUETOOTH_ENABLE - // if music rfid was read, go back to normal mode - if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { - System_SetOperationMode(OPMODE_NORMAL); - } - #endif + strncpy(gOldRfidTagId, gCurrentRfidTagId, 12); + } + #endif + #ifdef MQTT_ENABLE + publishMqtt(topicRfidState, gCurrentRfidTagId, false); + #endif - AudioPlayer_TrackQueueDispatcher(_file, _lastPlayPos, _playMode, _trackLastPlayed); + #ifdef BLUETOOTH_ENABLE + // if music rfid was read, go back to normal mode + if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { + System_SetOperationMode(OPMODE_NORMAL); } + #endif + + AudioPlayer_TrackQueueDispatcher(_file, _lastPlayPos, _playMode, _trackLastPlayed); } } - #endif + } +#endif } #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE -void Rfid_ResetOldRfid(){ - strncpy(gOldRfidTagId, "X", cardIdStringSize-1); +void Rfid_ResetOldRfid() { + strncpy(gOldRfidTagId, "X", cardIdStringSize - 1); } #endif -#if defined (RFID_READER_ENABLED) - extern TaskHandle_t rfidTaskHandle; +#if defined(RFID_READER_ENABLED) +extern TaskHandle_t rfidTaskHandle; #endif void Rfid_TaskPause(void) { - #if defined (RFID_READER_ENABLED) - vTaskSuspend(rfidTaskHandle); - #endif +#if defined(RFID_READER_ENABLED) + vTaskSuspend(rfidTaskHandle); +#endif } void Rfid_TaskResume(void) { - #if defined (RFID_READER_ENABLED) - vTaskResume(rfidTaskHandle); - #endif +#if defined(RFID_READER_ENABLED) + vTaskResume(rfidTaskHandle); +#endif } - diff --git a/src/RfidMfrc522.cpp b/src/RfidMfrc522.cpp index 34c42aaa..f59e3144 100644 --- a/src/RfidMfrc522.cpp +++ b/src/RfidMfrc522.cpp @@ -1,13 +1,15 @@ #include #include "settings.h" -#include "Rfid.h" + +#include "AudioPlayer.h" +#include "HallEffectSensor.h" #include "Log.h" #include "MemX.h" #include "Queues.h" +#include "Rfid.h" #include "System.h" + #include -#include "AudioPlayer.h" -#include "HallEffectSensor.h" #if defined RFID_READER_TYPE_MFRC522_SPI || defined RFID_READER_TYPE_MFRC522_I2C #ifdef RFID_READER_TYPE_MFRC522_SPI @@ -20,181 +22,181 @@ #include #endif - extern unsigned long Rfid_LastRfidCheckTimestamp; - TaskHandle_t rfidTaskHandle; - static void Rfid_Task(void *parameter); +extern unsigned long Rfid_LastRfidCheckTimestamp; +TaskHandle_t rfidTaskHandle; +static void Rfid_Task(void *parameter); #ifdef RFID_READER_TYPE_MFRC522_I2C - extern TwoWire i2cBusTwo; - static MFRC522_I2C mfrc522(MFRC522_ADDR, MFRC522_RST_PIN, &i2cBusTwo); +extern TwoWire i2cBusTwo; +static MFRC522_I2C mfrc522(MFRC522_ADDR, MFRC522_RST_PIN, &i2cBusTwo); #endif #ifdef RFID_READER_TYPE_MFRC522_SPI - static MFRC522 mfrc522(RFID_CS, RST_PIN); +static MFRC522 mfrc522(RFID_CS, RST_PIN); #endif - void Rfid_Init(void) { - #ifdef RFID_READER_TYPE_MFRC522_SPI - SPI.begin(RFID_SCK, RFID_MISO, RFID_MOSI, RFID_CS); - SPI.setFrequency(1000000); - #endif +void Rfid_Init(void) { + #ifdef RFID_READER_TYPE_MFRC522_SPI + SPI.begin(RFID_SCK, RFID_MISO, RFID_MOSI, RFID_CS); + SPI.setFrequency(1000000); + #endif - // Init RC522 Card-Reader - #if defined(RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_MFRC522_SPI) - mfrc522.PCD_Init(); - mfrc522.PCD_SetAntennaGain(rfidGain); - delay(50); - Log_Println(rfidScannerReady, LOGLEVEL_DEBUG); - - xTaskCreatePinnedToCore( - Rfid_Task, /* Function to implement the task */ - "rfid", /* Name of the task */ - 2048, /* Stack size in words */ - NULL, /* Task input parameter */ - 2 | portPRIVILEGE_BIT, /* Priority of the task */ - &rfidTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ - ); - #endif - } + // Init RC522 Card-Reader + #if defined(RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_MFRC522_SPI) + mfrc522.PCD_Init(); + mfrc522.PCD_SetAntennaGain(rfidGain); + delay(50); + Log_Println(rfidScannerReady, LOGLEVEL_DEBUG); + + xTaskCreatePinnedToCore( + Rfid_Task, /* Function to implement the task */ + "rfid", /* Name of the task */ + 2048, /* Stack size in words */ + NULL, /* Task input parameter */ + 2 | portPRIVILEGE_BIT, /* Priority of the task */ + &rfidTaskHandle, /* Task handle. */ + 1 /* Core where the task should run */ + ); + #endif +} - void Rfid_Task(void *parameter) { - #ifdef PAUSE_WHEN_RFID_REMOVED - uint8_t control = 0x00; - #endif +void Rfid_Task(void *parameter) { + #ifdef PAUSE_WHEN_RFID_REMOVED + uint8_t control = 0x00; + #endif - for (;;) { - if (RFID_SCAN_INTERVAL/2 >= 20) { - vTaskDelay(portTICK_PERIOD_MS * (RFID_SCAN_INTERVAL/2)); - } else { - vTaskDelay(portTICK_PERIOD_MS * 20); + for (;;) { + if (RFID_SCAN_INTERVAL / 2 >= 20) { + vTaskDelay(portTICK_PERIOD_MS * (RFID_SCAN_INTERVAL / 2)); + } else { + vTaskDelay(portTICK_PERIOD_MS * 20); + } + byte cardId[cardIdSize]; + String cardIdString; + #ifdef PAUSE_WHEN_RFID_REMOVED + byte lastValidcardId[cardIdSize]; + bool cardAppliedCurrentRun = false; + bool sameCardReapplied = false; + #endif + if ((millis() - Rfid_LastRfidCheckTimestamp) >= RFID_SCAN_INTERVAL) { + // Log_Printf(LOGLEVEL_DEBUG, "%u", uxTaskGetStackHighWaterMark(NULL)); + + Rfid_LastRfidCheckTimestamp = millis(); + // Reset the loop if no new card is present on the sensor/reader. This saves the entire process when idle. + + if (!mfrc522.PICC_IsNewCardPresent()) { + continue; } - byte cardId[cardIdSize]; - String cardIdString; - #ifdef PAUSE_WHEN_RFID_REMOVED - byte lastValidcardId[cardIdSize]; - bool cardAppliedCurrentRun = false; - bool sameCardReapplied = false; - #endif - if ((millis() - Rfid_LastRfidCheckTimestamp) >= RFID_SCAN_INTERVAL) { - //Log_Printf(LOGLEVEL_DEBUG, "%u", uxTaskGetStackHighWaterMark(NULL)); - - Rfid_LastRfidCheckTimestamp = millis(); - // Reset the loop if no new card is present on the sensor/reader. This saves the entire process when idle. - - if (!mfrc522.PICC_IsNewCardPresent()) { - continue; - } - // Select one of the cards - if (!mfrc522.PICC_ReadCardSerial()) { - continue; - } - #ifdef PAUSE_WHEN_RFID_REMOVED - cardAppliedCurrentRun = true; - #endif + // Select one of the cards + if (!mfrc522.PICC_ReadCardSerial()) { + continue; + } + #ifdef PAUSE_WHEN_RFID_REMOVED + cardAppliedCurrentRun = true; + #endif + + #ifndef PAUSE_WHEN_RFID_REMOVED + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); + #endif - #ifndef PAUSE_WHEN_RFID_REMOVED - mfrc522.PICC_HaltA(); - mfrc522.PCD_StopCrypto1(); - #endif + memcpy(cardId, mfrc522.uid.uidByte, cardIdSize); - memcpy(cardId, mfrc522.uid.uidByte, cardIdSize); + #ifdef HALLEFFECT_SENSOR_ENABLE + cardId[cardIdSize - 1] = cardId[cardIdSize - 1] + gHallEffectSensor.waitForState(HallEffectWaitMS); + #endif - #ifdef HALLEFFECT_SENSOR_ENABLE - cardId[cardIdSize-1] = cardId[cardIdSize-1] + gHallEffectSensor.waitForState(HallEffectWaitMS); - #endif + #ifdef PAUSE_WHEN_RFID_REMOVED + if (memcmp((const void *) lastValidcardId, (const void *) cardId, sizeof(cardId)) == 0) { + sameCardReapplied = true; + } + #endif - #ifdef PAUSE_WHEN_RFID_REMOVED - if (memcmp((const void *)lastValidcardId, (const void *)cardId, sizeof(cardId)) == 0) { - sameCardReapplied = true; - } - #endif + String hexString; + for (uint8_t i = 0u; i < cardIdSize; i++) { + char str[4]; + snprintf(str, sizeof(str), "%02x%c", cardId[i], (i < cardIdSize - 1u) ? '-' : ' '); + hexString += str; + } + Log_Printf(LOGLEVEL_NOTICE, rfidTagDetected, hexString.c_str()); - String hexString; - for (uint8_t i=0u; i < cardIdSize; i++) { - char str[4]; - snprintf(str, sizeof(str), "%02x%c", cardId[i], (i < cardIdSize - 1u) ? '-' : ' '); - hexString += str; - } - Log_Printf(LOGLEVEL_NOTICE, rfidTagDetected, hexString.c_str()); + for (uint8_t i = 0u; i < cardIdSize; i++) { + char num[4]; + snprintf(num, sizeof(num), "%03d", cardId[i]); + cardIdString += num; + } - for (uint8_t i=0u; i < cardIdSize; i++) { - char num[4]; - snprintf(num, sizeof(num), "%03d", cardId[i]); - cardIdString += num; + #ifdef PAUSE_WHEN_RFID_REMOVED + #ifdef ACCEPT_SAME_RFID_AFTER_TRACK_END + if (!sameCardReapplied || gPlayProperties.trackFinished || gPlayProperties.playlistFinished) { // Don't allow to send card to queue if it's the same card again if track or playlist is unfnished + #else + if (!sameCardReapplied) { // Don't allow to send card to queue if it's the same card again... + #endif + xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); + } 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) } + } + memcpy(lastValidcardId, mfrc522.uid.uidByte, cardIdSize); + #else + xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); // If PAUSE_WHEN_RFID_REMOVED isn't active, every card-apply leads to new playlist-generation + #endif - #ifdef PAUSE_WHEN_RFID_REMOVED - #ifdef ACCEPT_SAME_RFID_AFTER_TRACK_END - if (!sameCardReapplied || gPlayProperties.trackFinished || gPlayProperties.playlistFinished) { // Don't allow to send card to queue if it's the same card again if track or playlist is unfnished - #else - if (!sameCardReapplied) { // Don't allow to send card to queue if it's the same card again... - #endif - xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); - } 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) - } - } - memcpy(lastValidcardId, mfrc522.uid.uidByte, cardIdSize); - #else - xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); // If PAUSE_WHEN_RFID_REMOVED isn't active, every card-apply leads to new playlist-generation - #endif - - #ifdef PAUSE_WHEN_RFID_REMOVED - // https://github.com/miguelbalboa/rfid/issues/188; voodoo! :-) - while (true) { - if (RFID_SCAN_INTERVAL/2 >= 20) { - vTaskDelay(portTICK_PERIOD_MS * (RFID_SCAN_INTERVAL/2)); - } else { - vTaskDelay(portTICK_PERIOD_MS * 20); - } - control=0; - for (uint8_t i=0u; i<3; i++) { - if (!mfrc522.PICC_IsNewCardPresent()) { - if (mfrc522.PICC_ReadCardSerial()) { - control |= 0x16; - } - if (mfrc522.PICC_ReadCardSerial()) { - control |= 0x16; - } - control += 0x1; - } - control += 0x4; + #ifdef PAUSE_WHEN_RFID_REMOVED + // https://github.com/miguelbalboa/rfid/issues/188; voodoo! :-) + while (true) { + if (RFID_SCAN_INTERVAL / 2 >= 20) { + vTaskDelay(portTICK_PERIOD_MS * (RFID_SCAN_INTERVAL / 2)); + } else { + vTaskDelay(portTICK_PERIOD_MS * 20); + } + control = 0; + for (uint8_t i = 0u; i < 3; i++) { + if (!mfrc522.PICC_IsNewCardPresent()) { + if (mfrc522.PICC_ReadCardSerial()) { + control |= 0x16; } - - if (control == 13 || control == 14) { - //card is still there - } else { - break; + if (mfrc522.PICC_ReadCardSerial()) { + control |= 0x16; } + control += 0x1; } + control += 0x4; + } - Log_Println(rfidTagRemoved, LOGLEVEL_NOTICE); - if (!gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); - Log_Println(rfidTagReapplied, LOGLEVEL_NOTICE); - } - mfrc522.PICC_HaltA(); - mfrc522.PCD_StopCrypto1(); - cardAppliedCurrentRun = false; - #endif + if (control == 13 || control == 14) { + // card is still there + } else { + break; + } + } + + Log_Println(rfidTagRemoved, LOGLEVEL_NOTICE); + if (!gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { + AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + Log_Println(rfidTagReapplied, LOGLEVEL_NOTICE); } + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); + cardAppliedCurrentRun = false; + #endif } } +} - void Rfid_Cyclic(void) { - // Not necessary as cyclic stuff performed by task Rfid_Task() - } +void Rfid_Cyclic(void) { + // Not necessary as cyclic stuff performed by task Rfid_Task() +} - void Rfid_Exit(void) { - #ifndef RFID_READER_TYPE_MFRC522_I2C - mfrc522.PCD_SoftPowerDown(); - #endif - } +void Rfid_Exit(void) { + #ifndef RFID_READER_TYPE_MFRC522_I2C + mfrc522.PCD_SoftPowerDown(); + #endif +} - void Rfid_WakeupCheck(void) { - } +void Rfid_WakeupCheck(void) { +} #endif diff --git a/src/RfidPn5180.cpp b/src/RfidPn5180.cpp index 7b10c669..b5b0da40 100644 --- a/src/RfidPn5180.cpp +++ b/src/RfidPn5180.cpp @@ -1,16 +1,18 @@ #include -#include -#include -#include #include "settings.h" -#include "Rfid.h" + +#include "AudioPlayer.h" +#include "HallEffectSensor.h" #include "Log.h" #include "MemX.h" +#include "Port.h" #include "Queues.h" +#include "Rfid.h" #include "System.h" -#include "Port.h" -#include "AudioPlayer.h" -#include "HallEffectSensor.h" + +#include +#include +#include #ifdef RFID_READER_TYPE_PN5180 #include @@ -20,375 +22,375 @@ #define RFID_PN5180_STATE_INIT 0u -#define RFID_PN5180_NFC14443_STATE_RESET 1u +#define RFID_PN5180_NFC14443_STATE_RESET 1u #define RFID_PN5180_NFC14443_STATE_READCARD 2u -#define RFID_PN5180_NFC14443_STATE_ACTIVE 99u +#define RFID_PN5180_NFC14443_STATE_ACTIVE 99u -#define RFID_PN5180_NFC15693_STATE_RESET 3u -#define RFID_PN5180_NFC15693_STATE_SETUPRF 4u -#define RFID_PN5180_NFC15693_STATE_GETINVENTORY 5u -#define RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE 6u +#define RFID_PN5180_NFC15693_STATE_RESET 3u +#define RFID_PN5180_NFC15693_STATE_SETUPRF 4u +#define RFID_PN5180_NFC15693_STATE_GETINVENTORY 5u +#define RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE 6u #define RFID_PN5180_NFC15693_STATE_GETINVENTORY_PRIVACY 7u -#define RFID_PN5180_NFC15693_STATE_ACTIVE 100u +#define RFID_PN5180_NFC15693_STATE_ACTIVE 100u extern unsigned long Rfid_LastRfidCheckTimestamp; #ifdef RFID_READER_TYPE_PN5180 - static void Rfid_Task(void *parameter); - TaskHandle_t rfidTaskHandle; +static void Rfid_Task(void *parameter); +TaskHandle_t rfidTaskHandle; #ifdef PN5180_ENABLE_LPCD - void Rfid_EnableLpcd(void); - bool enabledLpcdShutdown = false; // Indicates if LPCD should be activated as part of the shutdown-process +void Rfid_EnableLpcd(void); +bool enabledLpcdShutdown = false; // Indicates if LPCD should be activated as part of the shutdown-process - void Rfid_SetLpcdShutdownStatus(bool lpcdStatus) { - enabledLpcdShutdown = lpcdStatus; - } +void Rfid_SetLpcdShutdownStatus(bool lpcdStatus) { + enabledLpcdShutdown = lpcdStatus; +} - bool Rfid_GetLpcdShutdownStatus(void) { - return enabledLpcdShutdown; - } +bool Rfid_GetLpcdShutdownStatus(void) { + return enabledLpcdShutdown; +} #endif - void Rfid_Init(void) { - #ifdef PN5180_ENABLE_LPCD - // Check if wakeup-reason was card-detection (PN5180 only) - // This only works if RFID.IRQ is connected to a GPIO and not to a port-expander - esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); - if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT1) { - Rfid_WakeupCheck(); - } - // disable pin hold from deep sleep - gpio_deep_sleep_hold_dis(); - gpio_hold_dis(gpio_num_t(RFID_CS)); // NSS - gpio_hold_dis(gpio_num_t(RFID_RST)); // RST - #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) - pinMode(RFID_IRQ, INPUT); // Not necessary for port-expander as for pca9555 all pins are configured as input per default - #endif - #endif - - xTaskCreatePinnedToCore( - Rfid_Task, /* Function to implement the task */ - "rfid", /* Name of the task */ - 2048, /* Stack size in words */ - NULL, /* Task input parameter */ - 2 | portPRIVILEGE_BIT, /* Priority of the task */ - &rfidTaskHandle, /* Task handle. */ - 0 /* Core where the task should run */ - ); +void Rfid_Init(void) { + #ifdef PN5180_ENABLE_LPCD + // Check if wakeup-reason was card-detection (PN5180 only) + // This only works if RFID.IRQ is connected to a GPIO and not to a port-expander + esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause(); + if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT1) { + Rfid_WakeupCheck(); } + // disable pin hold from deep sleep + gpio_deep_sleep_hold_dis(); + gpio_hold_dis(gpio_num_t(RFID_CS)); // NSS + gpio_hold_dis(gpio_num_t(RFID_RST)); // RST + #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) + pinMode(RFID_IRQ, INPUT); // Not necessary for port-expander as for pca9555 all pins are configured as input per default + #endif + #endif - void Rfid_Cyclic(void) { - // Not necessary as cyclic stuff performed by task Rfid_Task() + xTaskCreatePinnedToCore( + Rfid_Task, /* Function to implement the task */ + "rfid", /* Name of the task */ + 2048, /* Stack size in words */ + NULL, /* Task input parameter */ + 2 | portPRIVILEGE_BIT, /* Priority of the task */ + &rfidTaskHandle, /* Task handle. */ + 0 /* Core where the task should run */ + ); +} + +void Rfid_Cyclic(void) { + // Not necessary as cyclic stuff performed by task Rfid_Task() +} + +void Rfid_Task(void *parameter) { + static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST); + static PN5180ISO15693 nfc15693(RFID_CS, RFID_BUSY, RFID_RST); + uint32_t lastTimeDetected14443 = 0; + uint32_t lastTimeDetected15693 = 0; + #ifdef PAUSE_WHEN_RFID_REMOVED + byte lastValidcardId[cardIdSize]; + bool cardAppliedCurrentRun = false; + bool cardAppliedLastRun = false; + #endif + uint8_t stateMachine = RFID_PN5180_STATE_INIT; + static byte cardId[cardIdSize], lastCardId[cardIdSize]; + uint8_t uid[10]; + bool showDisablePrivacyNotification = true; + + // wait until queues are created + while (gRfidCardQueue == NULL) { + Log_Println(waitingForTaskQueues, LOGLEVEL_DEBUG); + vTaskDelay(50); } - void Rfid_Task(void *parameter) { - static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST); - static PN5180ISO15693 nfc15693(RFID_CS, RFID_BUSY, RFID_RST); - uint32_t lastTimeDetected14443 = 0; - uint32_t lastTimeDetected15693 = 0; - #ifdef PAUSE_WHEN_RFID_REMOVED - byte lastValidcardId[cardIdSize]; - bool cardAppliedCurrentRun = false; - bool cardAppliedLastRun = false; - #endif - uint8_t stateMachine = RFID_PN5180_STATE_INIT; - static byte cardId[cardIdSize], lastCardId[cardIdSize]; - uint8_t uid[10]; - bool showDisablePrivacyNotification = true; - - // wait until queues are created - while (gRfidCardQueue == NULL) { - Log_Println(waitingForTaskQueues, LOGLEVEL_DEBUG); - vTaskDelay(50); + for (;;) { + vTaskDelay(portTICK_PERIOD_MS * 10u); + #ifdef PN5180_ENABLE_LPCD + if (Rfid_GetLpcdShutdownStatus()) { + Rfid_EnableLpcd(); + Rfid_SetLpcdShutdownStatus(false); // give feedback that execution is complete + while (true) { + vTaskDelay(portTICK_PERIOD_MS * 100u); // there's no way back if shutdown was initiated + } } + #endif + String cardIdString; + bool cardReceived = false; + #ifdef PAUSE_WHEN_RFID_REMOVED + bool sameCardReapplied = false; + #endif - for (;;) { - vTaskDelay(portTICK_PERIOD_MS * 10u); - #ifdef PN5180_ENABLE_LPCD - if (Rfid_GetLpcdShutdownStatus()) { - Rfid_EnableLpcd(); - Rfid_SetLpcdShutdownStatus(false); // give feedback that execution is complete - while (true) { - vTaskDelay(portTICK_PERIOD_MS * 100u); // there's no way back if shutdown was initiated - } - } - #endif - String cardIdString; - bool cardReceived = false; - #ifdef PAUSE_WHEN_RFID_REMOVED - bool sameCardReapplied = false; - #endif - - if (RFID_PN5180_STATE_INIT == stateMachine) { - nfc14443.begin(); - nfc14443.reset(); - // show PN5180 reader version - uint8_t firmwareVersion[2]; - nfc14443.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion)); - Log_Printf(LOGLEVEL_DEBUG, "PN5180 firmware version=%d.%d", firmwareVersion[1], firmwareVersion[0]); - - // activate RF field - delay(4u); - Log_Println(rfidScannerReady, LOGLEVEL_DEBUG); + if (RFID_PN5180_STATE_INIT == stateMachine) { + nfc14443.begin(); + nfc14443.reset(); + // show PN5180 reader version + uint8_t firmwareVersion[2]; + nfc14443.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion)); + Log_Printf(LOGLEVEL_DEBUG, "PN5180 firmware version=%d.%d", firmwareVersion[1], firmwareVersion[0]); + + // activate RF field + delay(4u); + Log_Println(rfidScannerReady, LOGLEVEL_DEBUG); // 1. check for an ISO-14443 card - } else if (RFID_PN5180_NFC14443_STATE_RESET == stateMachine) { - nfc14443.reset(); - //Log_Printf(LOGLEVEL_DEBUG, "%u", uxTaskGetStackHighWaterMark(NULL)); - } else if (RFID_PN5180_NFC14443_STATE_READCARD == stateMachine) { - - if (nfc14443.readCardSerial(uid) >= 4) { - cardReceived = true; - stateMachine = RFID_PN5180_NFC14443_STATE_ACTIVE; - lastTimeDetected14443 = millis(); - #ifdef PAUSE_WHEN_RFID_REMOVED - cardAppliedCurrentRun = true; - #endif - } else { - // Reset to dummy-value if no card is there - // Necessary to differentiate between "card is still applied" and "card is re-applied again after removal" - // lastTimeDetected14443 is used to prevent "new card detection with old card" with single events where no card was detected - if (!lastTimeDetected14443 || (millis() - lastTimeDetected14443 >= 1000)) { - lastTimeDetected14443 = 0; - #ifdef PAUSE_WHEN_RFID_REMOVED - cardAppliedCurrentRun = false; - #endif - for (uint8_t i=0; i= 4) { + cardReceived = true; + stateMachine = RFID_PN5180_NFC14443_STATE_ACTIVE; + lastTimeDetected14443 = millis(); + #ifdef PAUSE_WHEN_RFID_REMOVED + cardAppliedCurrentRun = true; + #endif + } else { + // Reset to dummy-value if no card is there + // Necessary to differentiate between "card is still applied" and "card is re-applied again after removal" + // lastTimeDetected14443 is used to prevent "new card detection with old card" with single events where no card was detected + if (!lastTimeDetected14443 || (millis() - lastTimeDetected14443 >= 1000)) { + lastTimeDetected14443 = 0; + #ifdef PAUSE_WHEN_RFID_REMOVED + cardAppliedCurrentRun = false; + #endif + for (uint8_t i = 0; i < cardIdSize; i++) { + lastCardId[i] = 0; } + } else { + stateMachine = RFID_PN5180_NFC14443_STATE_ACTIVE; // Still consider first event as "active" } + } // 2. check for an ISO-15693 card - } else if (RFID_PN5180_NFC15693_STATE_RESET == stateMachine) { - nfc15693.reset(); - } else if (RFID_PN5180_NFC15693_STATE_SETUPRF == stateMachine) { - nfc15693.setupRF(); - } else if (RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE == stateMachine) { - // check for ICODE-SLIX2 password protected tag - // put your privacy password here, e.g.: - // https://de.ifixit.com/Antworten/Ansehen/513422/nfc+Chips+f%C3%BCr+tonies+kaufen - // - // default factory password for ICODE-SLIX2 is {0x0F, 0x0F, 0x0F, 0x0F} - // - uint8_t password[] = {0x0F, 0x0F, 0x0F, 0x0F}; - ISO15693ErrorCode myrc = nfc15693.disablePrivacyMode(password); - if (ISO15693_EC_OK == myrc) { - if (showDisablePrivacyNotification) { - showDisablePrivacyNotification = false; - Log_Println("disabling privacy-mode successful", LOGLEVEL_NOTICE); - } else { - // no privacy mode or disabling failed, skip next steps & restart state machine - stateMachine = RFID_PN5180_NFC15693_STATE_GETINVENTORY_PRIVACY; - } - } - } else if ((RFID_PN5180_NFC15693_STATE_GETINVENTORY == stateMachine) || (RFID_PN5180_NFC15693_STATE_GETINVENTORY_PRIVACY == stateMachine)) { - // try to read ISO15693 inventory - ISO15693ErrorCode rc = nfc15693.getInventory(uid); - if (rc == ISO15693_EC_OK) { - cardReceived = true; - stateMachine = RFID_PN5180_NFC15693_STATE_ACTIVE; - lastTimeDetected15693 = millis(); - #ifdef PAUSE_WHEN_RFID_REMOVED - cardAppliedCurrentRun = true; - #endif + } else if (RFID_PN5180_NFC15693_STATE_RESET == stateMachine) { + nfc15693.reset(); + } else if (RFID_PN5180_NFC15693_STATE_SETUPRF == stateMachine) { + nfc15693.setupRF(); + } else if (RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE == stateMachine) { + // check for ICODE-SLIX2 password protected tag + // put your privacy password here, e.g.: + // https://de.ifixit.com/Antworten/Ansehen/513422/nfc+Chips+f%C3%BCr+tonies+kaufen + // + // default factory password for ICODE-SLIX2 is {0x0F, 0x0F, 0x0F, 0x0F} + // + uint8_t password[] = {0x0F, 0x0F, 0x0F, 0x0F}; + ISO15693ErrorCode myrc = nfc15693.disablePrivacyMode(password); + if (ISO15693_EC_OK == myrc) { + if (showDisablePrivacyNotification) { + showDisablePrivacyNotification = false; + Log_Println("disabling privacy-mode successful", LOGLEVEL_NOTICE); } else { - // lastTimeDetected15693 is used to prevent "new card detection with old card" with single events where no card was detected - if (!lastTimeDetected15693 || (millis() - lastTimeDetected15693 >= 400)) { - lastTimeDetected15693 = 0; - #ifdef PAUSE_WHEN_RFID_REMOVED - cardAppliedCurrentRun = false; - #endif - for (uint8_t i=0; i pause - AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); - Log_Println(rfidTagRemoved, LOGLEVEL_NOTICE); - } - cardAppliedLastRun = cardAppliedCurrentRun; - #endif - - // send card to queue - if (cardReceived) { - memcpy(cardId, uid, cardIdSize); - - // check for different card id - if (memcmp((const void *)cardId, (const void *)lastCardId, sizeof(cardId)) == 0) { - // reset state machine - if (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) { - stateMachine = RFID_PN5180_NFC14443_STATE_RESET; - continue; - } else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) { - stateMachine = RFID_PN5180_NFC15693_STATE_RESET; - continue; + } else if ((RFID_PN5180_NFC15693_STATE_GETINVENTORY == stateMachine) || (RFID_PN5180_NFC15693_STATE_GETINVENTORY_PRIVACY == stateMachine)) { + // try to read ISO15693 inventory + ISO15693ErrorCode rc = nfc15693.getInventory(uid); + if (rc == ISO15693_EC_OK) { + cardReceived = true; + stateMachine = RFID_PN5180_NFC15693_STATE_ACTIVE; + lastTimeDetected15693 = millis(); + #ifdef PAUSE_WHEN_RFID_REMOVED + cardAppliedCurrentRun = true; + #endif + } else { + // lastTimeDetected15693 is used to prevent "new card detection with old card" with single events where no card was detected + if (!lastTimeDetected15693 || (millis() - lastTimeDetected15693 >= 400)) { + lastTimeDetected15693 = 0; + #ifdef PAUSE_WHEN_RFID_REMOVED + cardAppliedCurrentRun = false; + #endif + for (uint8_t i = 0; i < cardIdSize; i++) { + lastCardId[i] = 0; } + } else { + stateMachine = RFID_PN5180_NFC15693_STATE_ACTIVE; } + } + } - memcpy(lastCardId, cardId, cardIdSize); - showDisablePrivacyNotification = true; - - #ifdef HALLEFFECT_SENSOR_ENABLE - cardId[cardIdSize-1] = cardId[cardIdSize-1] + gHallEffectSensor.waitForState(HallEffectWaitMS); - #endif + #ifdef PAUSE_WHEN_RFID_REMOVED + if (!cardAppliedCurrentRun && cardAppliedLastRun && !gPlayProperties.pausePlay && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { // Card removed => pause + AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); + Log_Println(rfidTagRemoved, LOGLEVEL_NOTICE); + } + cardAppliedLastRun = cardAppliedCurrentRun; + #endif - #ifdef PAUSE_WHEN_RFID_REMOVED - if (memcmp((const void *)lastValidcardId, (const void *)cardId, sizeof(cardId)) == 0) { - sameCardReapplied = true; - } - #endif + // send card to queue + if (cardReceived) { + memcpy(cardId, uid, cardIdSize); - String hexString; - for (uint8_t i = 0u; i < cardIdSize; i++) { - char str[4]; - snprintf(str, sizeof(str), "%02x%c", cardId[i], (i < cardIdSize - 1u) ? '-' : ' '); - hexString += str; + // check for different card id + if (memcmp((const void *) cardId, (const void *) lastCardId, sizeof(cardId)) == 0) { + // reset state machine + if (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) { + stateMachine = RFID_PN5180_NFC14443_STATE_RESET; + continue; + } else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) { + stateMachine = RFID_PN5180_NFC15693_STATE_RESET; + continue; } - Log_Printf(LOGLEVEL_NOTICE, rfidTagDetected, hexString.c_str()); - Log_Printf(LOGLEVEL_NOTICE, "Card type: %s", (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) ? "ISO-14443" : "ISO-15693"); + } - for (uint8_t i = 0u; i < cardIdSize; i++) { - char num[4]; - snprintf(num, sizeof(num), "%03d", cardId[i]); - cardIdString += num; - } + memcpy(lastCardId, cardId, cardIdSize); + showDisablePrivacyNotification = true; - #ifdef PAUSE_WHEN_RFID_REMOVED - #ifdef ACCEPT_SAME_RFID_AFTER_TRACK_END - if (!sameCardReapplied || gPlayProperties.trackFinished || gPlayProperties.playlistFinished) { // Don't allow to send card to queue if it's the same card again if track or playlist is unfnished - #else - if (!sameCardReapplied) { // Don't allow to send card to queue if it's the same card again... - #endif - xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); - } 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 - Log_Println(rfidTagReapplied, LOGLEVEL_NOTICE); - } - } - memcpy(lastValidcardId, uid, cardIdSize); - #else - xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); // If PAUSE_WHEN_RFID_REMOVED isn't active, every card-apply leads to new playlist-generation - #endif + #ifdef HALLEFFECT_SENSOR_ENABLE + cardId[cardIdSize - 1] = cardId[cardIdSize - 1] + gHallEffectSensor.waitForState(HallEffectWaitMS); + #endif + + #ifdef PAUSE_WHEN_RFID_REMOVED + if (memcmp((const void *) lastValidcardId, (const void *) cardId, sizeof(cardId)) == 0) { + sameCardReapplied = true; } + #endif - if (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) { // If 14443 is active, bypass 15693 as next check (performance) - stateMachine = RFID_PN5180_NFC14443_STATE_RESET; - } else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) { // If 15693 is active, bypass 14443 as next check (performance) - stateMachine = RFID_PN5180_NFC15693_STATE_RESET; + String hexString; + for (uint8_t i = 0u; i < cardIdSize; i++) { + char str[4]; + snprintf(str, sizeof(str), "%02x%c", cardId[i], (i < cardIdSize - 1u) ? '-' : ' '); + hexString += str; + } + Log_Printf(LOGLEVEL_NOTICE, rfidTagDetected, hexString.c_str()); + Log_Printf(LOGLEVEL_NOTICE, "Card type: %s", (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) ? "ISO-14443" : "ISO-15693"); + + for (uint8_t i = 0u; i < cardIdSize; i++) { + char num[4]; + snprintf(num, sizeof(num), "%03d", cardId[i]); + cardIdString += num; + } + + #ifdef PAUSE_WHEN_RFID_REMOVED + #ifdef ACCEPT_SAME_RFID_AFTER_TRACK_END + if (!sameCardReapplied || gPlayProperties.trackFinished || gPlayProperties.playlistFinished) { // Don't allow to send card to queue if it's the same card again if track or playlist is unfnished + #else + if (!sameCardReapplied) { // Don't allow to send card to queue if it's the same card again... + #endif + xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); } else { - stateMachine++; - if (stateMachine > RFID_PN5180_NFC15693_STATE_GETINVENTORY_PRIVACY) { - stateMachine = RFID_PN5180_NFC14443_STATE_RESET; + // 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 + Log_Println(rfidTagReapplied, LOGLEVEL_NOTICE); } } + memcpy(lastValidcardId, uid, cardIdSize); + #else + xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); // If PAUSE_WHEN_RFID_REMOVED isn't active, every card-apply leads to new playlist-generation + #endif } - } - void Rfid_Exit(void) { - #ifdef PN5180_ENABLE_LPCD - Rfid_SetLpcdShutdownStatus(true); - while (Rfid_GetLpcdShutdownStatus()) { // Make sure init of LPCD is complete! - vTaskDelay(portTICK_PERIOD_MS * 10u); + if (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) { // If 14443 is active, bypass 15693 as next check (performance) + stateMachine = RFID_PN5180_NFC14443_STATE_RESET; + } else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) { // If 15693 is active, bypass 14443 as next check (performance) + stateMachine = RFID_PN5180_NFC15693_STATE_RESET; + } else { + stateMachine++; + if (stateMachine > RFID_PN5180_NFC15693_STATE_GETINVENTORY_PRIVACY) { + stateMachine = RFID_PN5180_NFC14443_STATE_RESET; } - #endif - vTaskDelete(rfidTaskHandle); + } } +} - // Handles activation of LPCD (while shutdown is in progress) - void Rfid_EnableLpcd(void) { - // goto low power card detection mode - #ifdef PN5180_ENABLE_LPCD - static PN5180 nfc(RFID_CS, RFID_BUSY, RFID_RST); - nfc.begin(); - nfc.reset(); - // show PN5180 reader version - uint8_t firmwareVersion[2]; - nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion)); - Log_Printf(LOGLEVEL_DEBUG, "PN5180 firmware version=%d.%d", firmwareVersion[1], firmwareVersion[0]); +void Rfid_Exit(void) { + #ifdef PN5180_ENABLE_LPCD + Rfid_SetLpcdShutdownStatus(true); + while (Rfid_GetLpcdShutdownStatus()) { // Make sure init of LPCD is complete! + vTaskDelay(portTICK_PERIOD_MS * 10u); + } + #endif + vTaskDelete(rfidTaskHandle); +} - // check firmware version: PN5180 firmware < 4.0 has several bugs preventing the LPCD mode - // you can flash latest firmware with this project: https://github.com/abidxraihan/PN5180_Updater_ESP32 - if (firmwareVersion[1] < 4) { - Log_Println("This PN5180 firmware does not work with LPCD! use firmware >= 4.0", LOGLEVEL_ERROR); - return; - } - Log_Println("prepare low power card detection...", LOGLEVEL_NOTICE); - uint8_t irqConfig = 0b0000000; // Set IRQ active low + clear IRQ-register - nfc.writeEEprom(IRQ_PIN_CONFIG, &irqConfig, 1); - /* - nfc.readEEprom(IRQ_PIN_CONFIG, &irqConfig, 1); - Log_Printf("IRQ_PIN_CONFIG=0x%02X", irqConfig) - */ - nfc.prepareLPCD(); - Log_Printf(LOGLEVEL_DEBUG, "PN5180 IRQ PIN (%d) state: %d", RFID_IRQ, Port_Read(RFID_IRQ)); - // turn on LPCD - uint16_t wakeupCounterInMs = 0x3FF; // must be in the range of 0x0 - 0xA82. max wake-up time is 2960 ms. - if (nfc.switchToLPCD(wakeupCounterInMs)) { - Log_Println("switch to low power card detection: success", LOGLEVEL_NOTICE); - // configure wakeup pin for deep-sleep wake-up, use ext1. For a real GPIO only, not PE - #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) - if (ESP_ERR_INVALID_ARG == esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ALL_LOW)) { - Log_Printf(LOGLEVEL_ERROR, wrongWakeUpGpio, RFID_IRQ); - } - #endif - // freeze pin states in deep sleep - gpio_hold_en(gpio_num_t(RFID_CS)); // CS/NSS - gpio_hold_en(gpio_num_t(RFID_RST)); // RST - gpio_deep_sleep_hold_en(); - } else { - Log_Println("switchToLPCD failed", LOGLEVEL_ERROR); - } +// Handles activation of LPCD (while shutdown is in progress) +void Rfid_EnableLpcd(void) { + // goto low power card detection mode + #ifdef PN5180_ENABLE_LPCD + static PN5180 nfc(RFID_CS, RFID_BUSY, RFID_RST); + nfc.begin(); + nfc.reset(); + // show PN5180 reader version + uint8_t firmwareVersion[2]; + nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion)); + Log_Printf(LOGLEVEL_DEBUG, "PN5180 firmware version=%d.%d", firmwareVersion[1], firmwareVersion[0]); + + // check firmware version: PN5180 firmware < 4.0 has several bugs preventing the LPCD mode + // you can flash latest firmware with this project: https://github.com/abidxraihan/PN5180_Updater_ESP32 + if (firmwareVersion[1] < 4) { + Log_Println("This PN5180 firmware does not work with LPCD! use firmware >= 4.0", LOGLEVEL_ERROR); + return; + } + Log_Println("prepare low power card detection...", LOGLEVEL_NOTICE); + uint8_t irqConfig = 0b0000000; // Set IRQ active low + clear IRQ-register + nfc.writeEEprom(IRQ_PIN_CONFIG, &irqConfig, 1); + /* + nfc.readEEprom(IRQ_PIN_CONFIG, &irqConfig, 1); + Log_Printf("IRQ_PIN_CONFIG=0x%02X", irqConfig) + */ + nfc.prepareLPCD(); + Log_Printf(LOGLEVEL_DEBUG, "PN5180 IRQ PIN (%d) state: %d", RFID_IRQ, Port_Read(RFID_IRQ)); + // turn on LPCD + uint16_t wakeupCounterInMs = 0x3FF; // must be in the range of 0x0 - 0xA82. max wake-up time is 2960 ms. + if (nfc.switchToLPCD(wakeupCounterInMs)) { + Log_Println("switch to low power card detection: success", LOGLEVEL_NOTICE); + // configure wakeup pin for deep-sleep wake-up, use ext1. For a real GPIO only, not PE + #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) + if (ESP_ERR_INVALID_ARG == esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ALL_LOW)) { + Log_Printf(LOGLEVEL_ERROR, wrongWakeUpGpio, RFID_IRQ); + } #endif + // freeze pin states in deep sleep + gpio_hold_en(gpio_num_t(RFID_CS)); // CS/NSS + gpio_hold_en(gpio_num_t(RFID_RST)); // RST + gpio_deep_sleep_hold_en(); + } else { + Log_Println("switchToLPCD failed", LOGLEVEL_ERROR); } + #endif +} - // wake up from LPCD, check card is present. This works only for ISO-14443 compatible cards - void Rfid_WakeupCheck(void) { - #ifdef PN5180_ENABLE_LPCD - // disable pin hold from deep sleep - gpio_deep_sleep_hold_dis(); - gpio_hold_dis(gpio_num_t(RFID_CS)); // NSS - gpio_hold_dis(gpio_num_t(RFID_RST)); // RST - #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) - pinMode(RFID_IRQ, INPUT); - #endif - static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST); - nfc14443.begin(); - nfc14443.reset(); - // enable RF field - nfc14443.setupRF(); - if (!nfc14443.isCardPresent()) { - nfc14443.reset(); - uint16_t wakeupCounterInMs = 0x3FF; // needs to be in the range of 0x0 - 0xA82. max wake-up time is 2960 ms. - if (nfc14443.switchToLPCD(wakeupCounterInMs)) { - Log_Println(lowPowerCardSuccess, LOGLEVEL_INFO); - // configure wakeup pin for deep-sleep wake-up, use ext1 - #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) - // configure wakeup pin for deep-sleep wake-up, use ext1. For a real GPIO only, not PE - esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ALL_LOW); - #endif - // freeze pin states in deep sleep - gpio_hold_en(gpio_num_t(RFID_CS)); // CS/NSS - gpio_hold_en(gpio_num_t(RFID_RST)); // RST - gpio_deep_sleep_hold_en(); - Log_Println(wakeUpRfidNoIso14443, LOGLEVEL_ERROR); - esp_deep_sleep_start(); - } else { - Log_Println("switchToLPCD failed", LOGLEVEL_ERROR); - } - } - nfc14443.end(); +// wake up from LPCD, check card is present. This works only for ISO-14443 compatible cards +void Rfid_WakeupCheck(void) { + #ifdef PN5180_ENABLE_LPCD + // disable pin hold from deep sleep + gpio_deep_sleep_hold_dis(); + gpio_hold_dis(gpio_num_t(RFID_CS)); // NSS + gpio_hold_dis(gpio_num_t(RFID_RST)); // RST + #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) + pinMode(RFID_IRQ, INPUT); #endif + static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST); + nfc14443.begin(); + nfc14443.reset(); + // enable RF field + nfc14443.setupRF(); + if (!nfc14443.isCardPresent()) { + nfc14443.reset(); + uint16_t wakeupCounterInMs = 0x3FF; // needs to be in the range of 0x0 - 0xA82. max wake-up time is 2960 ms. + if (nfc14443.switchToLPCD(wakeupCounterInMs)) { + Log_Println(lowPowerCardSuccess, LOGLEVEL_INFO); + // configure wakeup pin for deep-sleep wake-up, use ext1 + #if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO) + // configure wakeup pin for deep-sleep wake-up, use ext1. For a real GPIO only, not PE + esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ALL_LOW); + #endif + // freeze pin states in deep sleep + gpio_hold_en(gpio_num_t(RFID_CS)); // CS/NSS + gpio_hold_en(gpio_num_t(RFID_RST)); // RST + gpio_deep_sleep_hold_en(); + Log_Println(wakeUpRfidNoIso14443, LOGLEVEL_ERROR); + esp_deep_sleep_start(); + } else { + Log_Println("switchToLPCD failed", LOGLEVEL_ERROR); + } } + nfc14443.end(); + #endif +} #endif diff --git a/src/RotaryEncoder.cpp b/src/RotaryEncoder.cpp index 9a9c09d0..7cec3a61 100644 --- a/src/RotaryEncoder.cpp +++ b/src/RotaryEncoder.cpp @@ -1,56 +1,59 @@ #include #include "settings.h" + #include "RotaryEncoder.h" + #include "AudioPlayer.h" #include "Log.h" #include "System.h" #ifdef USEROTARY_ENABLE -#include + #include #endif // Rotary encoder-configuration #ifdef USEROTARY_ENABLE - ESP32Encoder encoder; - // Rotary encoder-helper - int32_t lastEncoderValue; - int32_t currentEncoderValue; - int32_t lastVolume = -1; // Don't change -1 as initial-value! +ESP32Encoder encoder; +// Rotary encoder-helper +int32_t lastEncoderValue; +int32_t currentEncoderValue; +int32_t lastVolume = -1; // Don't change -1 as initial-value! #endif void RotaryEncoder_Init(void) { - // Init rotary encoder - #ifdef USEROTARY_ENABLE - #ifndef REVERSE_ROTARY - encoder.attachHalfQuad(ROTARYENCODER_CLK, ROTARYENCODER_DT); - #else - encoder.attachHalfQuad(ROTARYENCODER_DT, ROTARYENCODER_CLK); - #endif - encoder.clearCount(); +// Init rotary encoder +#ifdef USEROTARY_ENABLE + #ifndef REVERSE_ROTARY + encoder.attachHalfQuad(ROTARYENCODER_CLK, ROTARYENCODER_DT); + #else + encoder.attachHalfQuad(ROTARYENCODER_DT, ROTARYENCODER_CLK); #endif + encoder.clearCount(); +#endif } -void RotaryEncoder_Readjust(void) { } +void RotaryEncoder_Readjust(void) { +} // Handles volume directed by rotary encoder void RotaryEncoder_Cyclic(void) { - #ifdef USEROTARY_ENABLE - #ifdef INCLUDE_ROTARY_IN_CONTROLS_LOCK - if (System_AreControlsLocked()) { - encoder.clearCount(); - return; - } - #endif - - int32_t encoderValue = encoder.getCount(); - // Only if initial run or value has changed. And only after "full step" of rotary encoder - if ((encoderValue != 0) && (encoderValue % 2 == 0)) { - System_UpdateActivityTimer(); // Set inactivity back if rotary encoder was used - // 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); - return; - } +#ifdef USEROTARY_ENABLE + #ifdef INCLUDE_ROTARY_IN_CONTROLS_LOCK + if (System_AreControlsLocked()) { + encoder.clearCount(); + return; + } #endif + + int32_t encoderValue = encoder.getCount(); + // Only if initial run or value has changed. And only after "full step" of rotary encoder + if ((encoderValue != 0) && (encoderValue % 2 == 0)) { + System_UpdateActivityTimer(); // Set inactivity back if rotary encoder was used + // 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); + return; + } +#endif } diff --git a/src/SdCard.cpp b/src/SdCard.cpp index c898a865..e29746c0 100644 --- a/src/SdCard.cpp +++ b/src/SdCard.cpp @@ -1,6 +1,8 @@ #include #include "settings.h" + #include "SdCard.h" + #include "Common.h" #include "Led.h" #include "Log.h" @@ -8,94 +10,94 @@ #include "System.h" #ifdef SD_MMC_1BIT_MODE - fs::FS gFSystem = (fs::FS)SD_MMC; +fs::FS gFSystem = (fs::FS) SD_MMC; #else - SPIClass spiSD(HSPI); - fs::FS gFSystem = (fs::FS)SD; +SPIClass spiSD(HSPI); +fs::FS gFSystem = (fs::FS) SD; #endif void SdCard_Init(void) { - #ifdef NO_SDCARD - // Initialize without any SD card, e.g. for webplayer only - Log_Println("Init without SD card ", LOGLEVEL_NOTICE); - return - #endif - - #ifndef SINGLE_SPI_ENABLE - #ifdef SD_MMC_1BIT_MODE - pinMode(2, INPUT_PULLUP); - while (!SD_MMC.begin("/sdcard", true)) { - #else - pinMode(SPISD_CS, OUTPUT); - digitalWrite(SPISD_CS, HIGH); - spiSD.begin(SPISD_SCK, SPISD_MISO, SPISD_MOSI, SPISD_CS); - spiSD.setFrequency(1000000); - while (!SD.begin(SPISD_CS, spiSD)) { - #endif +#ifdef NO_SDCARD + // Initialize without any SD card, e.g. for webplayer only + Log_Println("Init without SD card ", LOGLEVEL_NOTICE); + return +#endif + +#ifndef SINGLE_SPI_ENABLE + #ifdef SD_MMC_1BIT_MODE + pinMode(2, INPUT_PULLUP); + while (!SD_MMC.begin("/sdcard", true)) { #else - #ifdef SD_MMC_1BIT_MODE - pinMode(2, INPUT_PULLUP); - while (!SD_MMC.begin("/sdcard", true)) { - #else - while (!SD.begin(SPISD_CS)) { - #endif + pinMode(SPISD_CS, OUTPUT); + digitalWrite(SPISD_CS, HIGH); + spiSD.begin(SPISD_SCK, SPISD_MISO, SPISD_MOSI, SPISD_CS); + spiSD.setFrequency(1000000); + while (!SD.begin(SPISD_CS, spiSD)) { #endif - Log_Println(unableToMountSd, LOGLEVEL_ERROR); - delay(500); - #ifdef SHUTDOWN_IF_SD_BOOT_FAILS - if (millis() >= deepsleepTimeAfterBootFails * 1000) { - Log_Println(sdBootFailedDeepsleep, LOGLEVEL_ERROR); - esp_deep_sleep_start(); - } +#else + #ifdef SD_MMC_1BIT_MODE + pinMode(2, INPUT_PULLUP); + while (!SD_MMC.begin("/sdcard", true)) { + #else + while (!SD.begin(SPISD_CS)) { #endif - } +#endif + Log_Println(unableToMountSd, LOGLEVEL_ERROR); + delay(500); +#ifdef SHUTDOWN_IF_SD_BOOT_FAILS + if (millis() >= deepsleepTimeAfterBootFails * 1000) { + Log_Println(sdBootFailedDeepsleep, LOGLEVEL_ERROR); + esp_deep_sleep_start(); + } +#endif + } } void SdCard_Exit(void) { - // SD card goto idle mode - #ifdef SINGLE_SPI_ENABLE - Log_Println("shutdown SD card (SPI)..", LOGLEVEL_NOTICE); - SD.end(); - #endif - #ifdef SD_MMC_1BIT_MODE - Log_Println("shutdown SD card (SD_MMC)..", LOGLEVEL_NOTICE); - SD_MMC.end(); - #endif +// SD card goto idle mode +#ifdef SINGLE_SPI_ENABLE + Log_Println("shutdown SD card (SPI)..", LOGLEVEL_NOTICE); + SD.end(); +#endif +#ifdef SD_MMC_1BIT_MODE + Log_Println("shutdown SD card (SD_MMC)..", LOGLEVEL_NOTICE); + SD_MMC.end(); +#endif } sdcard_type_t SdCard_GetType(void) { sdcard_type_t cardType; - #ifdef SD_MMC_1BIT_MODE - Log_Println(sdMountedMmc1BitMode, LOGLEVEL_NOTICE); - cardType = SD_MMC.cardType(); - #else - Log_Println(sdMountedSpiMode, LOGLEVEL_NOTICE); - cardType = SD.cardType(); - #endif - return cardType; +#ifdef SD_MMC_1BIT_MODE + Log_Println(sdMountedMmc1BitMode, LOGLEVEL_NOTICE); + cardType = SD_MMC.cardType(); +#else + Log_Println(sdMountedSpiMode, LOGLEVEL_NOTICE); + cardType = SD.cardType(); +#endif + return cardType; } uint64_t SdCard_GetSize() { - #ifdef SD_MMC_1BIT_MODE - return SD_MMC.cardSize(); - #else - return SD.cardSize(); - #endif +#ifdef SD_MMC_1BIT_MODE + return SD_MMC.cardSize(); +#else + return SD.cardSize(); +#endif } uint64_t SdCard_GetFreeSize() { - #ifdef SD_MMC_1BIT_MODE - return SD_MMC.cardSize() - SD_MMC.usedBytes(); - #else - return SD.cardSize() - SD.usedBytes(); - #endif +#ifdef SD_MMC_1BIT_MODE + return SD_MMC.cardSize() - SD_MMC.usedBytes(); +#else + return SD.cardSize() - SD.usedBytes(); +#endif } void SdCard_PrintInfo() { // show SD card type sdcard_type_t cardType = SdCard_GetType(); const char *type = "UNKNOWN"; - switch(cardType) { + switch (cardType) { case CARD_MMC: type = "MMC"; break; @@ -114,11 +116,11 @@ void SdCard_PrintInfo() { Log_Printf(LOGLEVEL_DEBUG, "SD card type: %s", type); // show SD card size / free space uint64_t cardSize = SdCard_GetSize() / (1024 * 1024); - uint64_t freeSize = SdCard_GetFreeSize() / (1024 * 1024);; + uint64_t freeSize = SdCard_GetFreeSize() / (1024 * 1024); + ; Log_Printf(LOGLEVEL_NOTICE, sdInfo, cardSize, freeSize); } - // Check if file-type is correct bool fileValid(const char *_fileItem) { // make file extension to lowercase (compare case insenstive) @@ -132,25 +134,14 @@ bool fileValid(const char *_fileItem) { char *subst; subst = strrchr(lFileItem, ch); // Don't use files that start with . bool isValid = (!startsWith(subst, (char *) "/.")) && ( - // audio file formats - endsWith(lFileItem, ".mp3") || - endsWith(lFileItem, ".aac") || - endsWith(lFileItem, ".m4a") || - endsWith(lFileItem, ".wav") || - endsWith(lFileItem, ".flac") || - endsWith(lFileItem, ".ogg") || - endsWith(lFileItem, ".oga") || - endsWith(lFileItem, ".opus") || - // playlist file formats - endsWith(lFileItem, ".m3u") || - endsWith(lFileItem, ".m3u8") || - endsWith(lFileItem, ".pls") || - endsWith(lFileItem, ".asx")); + // audio file formats + endsWith(lFileItem, ".mp3") || endsWith(lFileItem, ".aac") || endsWith(lFileItem, ".m4a") || endsWith(lFileItem, ".wav") || endsWith(lFileItem, ".flac") || endsWith(lFileItem, ".ogg") || endsWith(lFileItem, ".oga") || endsWith(lFileItem, ".opus") || + // playlist file formats + endsWith(lFileItem, ".m3u") || endsWith(lFileItem, ".m3u8") || endsWith(lFileItem, ".pls") || endsWith(lFileItem, ".asx")); free(lFileItem); return isValid; } - // Takes a directory as input and returns a random subdirectory from it char *SdCard_pickRandomSubdirectory(char *_directory) { uint32_t listStartTimestamp = millis(); @@ -164,9 +155,9 @@ char *SdCard_pickRandomSubdirectory(char *_directory) { Log_Printf(LOGLEVEL_NOTICE, tryToPickRandomDir, _directory); static uint8_t allocCount = 1; - uint16_t allocSize = psramInit() ? 65535 : 1024; // There's enough PSRAM. So we don't have to care... + uint16_t allocSize = psramInit() ? 65535 : 1024; // There's enough PSRAM. So we don't have to care... uint16_t directoryCount = 0; - char *buffer = _directory; // input char* is reused as it's content no longer needed + char *buffer = _directory; // input char* is reused as it's content no longer needed char *subdirectoryList = (char *) x_calloc(allocSize, sizeof(char)); if (subdirectoryList == NULL) { @@ -210,25 +201,25 @@ char *SdCard_pickRandomSubdirectory(char *_directory) { return NULL; } - uint16_t randomNumber = random(directoryCount) + 1; // Create random-number with max = subdirectory-count + uint16_t randomNumber = random(directoryCount) + 1; // Create random-number with max = subdirectory-count uint16_t delimiterFoundCount = 0; - uint32_t a=0; - uint8_t b=0; + uint32_t a = 0; + uint8_t b = 0; // Walk through subdirectory-array and extract randomized subdirectory while (subdirectoryList[a] != '\0') { if (subdirectoryList[a] == '#') { delimiterFoundCount++; } else { - if (delimiterFoundCount == randomNumber) { // Pick subdirectory of linear char* according to random number + if (delimiterFoundCount == randomNumber) { // Pick subdirectory of linear char* according to random number buffer[b++] = subdirectoryList[a]; } } - if (delimiterFoundCount > randomNumber || (b == 254)) { // It's over when next delimiter is found or buffer is full + if (delimiterFoundCount > randomNumber || (b == 254)) { // It's over when next delimiter is found or buffer is full buffer[b] = '\0'; free(subdirectoryList); Log_Printf(LOGLEVEL_NOTICE, pickedRandomDir, _directory); - return buffer; // Full path of random subdirectory + return buffer; // Full path of random subdirectory } a++; } @@ -238,14 +229,13 @@ char *SdCard_pickRandomSubdirectory(char *_directory) { return NULL; } - /* Puts SD-file(s) or directory into a playlist First element of array always contains the number of payload-items. */ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) { static char **files; char *serializedPlaylist = NULL; bool enablePlaylistFromM3u = false; - //uint32_t listStartTimestamp = millis(); + // uint32_t listStartTimestamp = millis(); if (files != NULL) { // If **ptr already exists, de-allocate its memory Log_Printf(LOGLEVEL_DEBUG, releaseMemoryOfOldPlaylist, ESP.getFreeHeap()); @@ -267,7 +257,7 @@ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) { if (fileOrDirectory && !fileOrDirectory.isDirectory() && fileOrDirectory.size() > 0) { enablePlaylistFromM3u = true; uint16_t allocCount = 1; - uint16_t allocSize = psramInit() ? 65535 : 1024; // There's enough PSRAM. So we don't have to care... + uint16_t allocSize = psramInit() ? 65535 : 1024; // There's enough PSRAM. So we don't have to care... serializedPlaylist = (char *) x_calloc(allocSize, sizeof(char)); if (serializedPlaylist == NULL) { @@ -286,8 +276,8 @@ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) { // skip M3U comment lines starting with # fileOrDirectory.readStringUntil('\n'); continue; - } - if (fPos+1 >= allocCount * allocSize) { + } + if (fPos + 1 >= allocCount * allocSize) { char *tmp = (char *) realloc(serializedPlaylist, ++allocCount * allocSize); Log_Println(reallocCalled, LOGLEVEL_DEBUG); if (tmp == NULL) { @@ -303,14 +293,14 @@ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) { serializedPlaylist[fPos++] = buf; lastBuf = buf; } else { - if (lastBuf != '#') { // Strip empty lines from m3u + if (lastBuf != '#') { // Strip empty lines from m3u serializedPlaylist[fPos++] = '#'; lastBuf = '#'; } } } - if (serializedPlaylist[fPos-1] == '#') { // Remove trailing delimiter if set - serializedPlaylist[fPos-1] = '\0'; + if (serializedPlaylist[fPos - 1] == '#') { // Remove trailing delimiter if set + serializedPlaylist[fPos - 1] = '\0'; } } else { return nullptr; @@ -414,7 +404,7 @@ char **SdCard_ReturnPlaylist(const char *fileName, const uint32_t _playMode) { freeMultiCharArray(files, cnt + 1); return nullptr; } - snprintf(files[0], 5, "%u", cnt); + snprintf(files[0], 5, "%u", cnt); Log_Printf(LOGLEVEL_NOTICE, numberOfValidFiles, cnt); // Log_Printf(LOGLEVEL_DEBUG, "build playlist from SD-card finished: %lu ms", (millis() - listStartTimestamp)); diff --git a/src/System.cpp b/src/System.cpp index e6d1c1db..a37b6711 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -1,32 +1,34 @@ #include #include "settings.h" + #include "System.h" + +#include "Audio.h" #include "AudioPlayer.h" -#include "Rfid.h" #include "Led.h" #include "Log.h" #include "Mqtt.h" -#include "SdCard.h" #include "Port.h" +#include "Power.h" +#include "Rfid.h" +#include "SdCard.h" +#include "esp_system.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "Audio.h" -#include "Power.h" -constexpr const char prefsRfidNamespace[] = "rfidTags"; // Namespace used to save IDs of rfid-tags +constexpr const char prefsRfidNamespace[] = "rfidTags"; // Namespace used to save IDs of rfid-tags constexpr const char prefsSettingsNamespace[] = "settings"; // Namespace used for generic settings Preferences gPrefsRfid; Preferences gPrefsSettings; -unsigned long System_LastTimeActiveTimestamp = 0u; // Timestamp of last user-interaction +unsigned long System_LastTimeActiveTimestamp = 0u; // Timestamp of last user-interaction unsigned long System_SleepTimerStartTimestamp = 0u; // Flag if sleep-timer is active -bool System_GoToSleep = false; // Flag for turning uC immediately into deepsleep -bool System_Sleeping = false; // Flag for turning into deepsleep is in progress -bool System_LockControls = false; // Flag if buttons and rotary encoder is locked -uint8_t System_MaxInactivityTime = 10u; // Time in minutes, after uC is put to deep sleep because of inactivity (and modified later via GUI) -uint8_t System_SleepTimer = 30u; // Sleep timer in minutes that can be optionally used (and modified later via MQTT or RFID) +bool System_GoToSleep = false; // Flag for turning uC immediately into deepsleep +bool System_Sleeping = false; // Flag for turning into deepsleep is in progress +bool System_LockControls = false; // Flag if buttons and rotary encoder is locked +uint8_t System_MaxInactivityTime = 10u; // Time in minutes, after uC is put to deep sleep because of inactivity (and modified later via GUI) +uint8_t System_SleepTimer = 30u; // Sleep timer in minutes that can be optionally used (and modified later via MQTT or RFID) // Operation Mode volatile uint8_t System_OperationMode; @@ -66,7 +68,6 @@ void System_RequestSleep(void) { System_GoToSleep = true; } - bool System_SetSleepTimer(uint8_t minutes) { bool sleepTimerEnabled = false; @@ -92,10 +93,10 @@ bool System_SetSleepTimer(uint8_t minutes) { } } - #ifdef MQTT_ENABLE - publishMqtt(topicSleepTimerState, System_GetSleepTimer(), false); - publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); - #endif +#ifdef MQTT_ENABLE + publishMqtt(topicSleepTimerState, System_GetSleepTimer(), false); + publishMqtt(topicLedBrightnessState, Led_GetBrightness(), false); +#endif return sleepTimerEnabled; } @@ -178,22 +179,22 @@ void System_SleepHandler(void) { void System_PreparePowerDown(void) { AudioPlayer_Exit(); - // Disable amps in order to avoid ugly noises when powering off - #ifdef GPIO_PA_EN - Log_Println("shutdown amplifier..", LOGLEVEL_NOTICE); - Port_Write(GPIO_PA_EN, false, false); - #endif - #ifdef GPIO_HP_EN - Log_Println("shutdown headphone..", LOGLEVEL_NOTICE); - Port_Write(GPIO_HP_EN, false, false); - #endif +// Disable amps in order to avoid ugly noises when powering off +#ifdef GPIO_PA_EN + Log_Println("shutdown amplifier..", LOGLEVEL_NOTICE); + Port_Write(GPIO_PA_EN, false, false); +#endif +#ifdef GPIO_HP_EN + Log_Println("shutdown headphone..", LOGLEVEL_NOTICE); + Port_Write(GPIO_HP_EN, false, false); +#endif Mqtt_Exit(); Led_Exit(); - #ifdef USE_LAST_VOLUME_AFTER_REBOOT - gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetCurrentVolume()); - #endif +#ifdef USE_LAST_VOLUME_AFTER_REBOOT + gPrefsSettings.putUInt("previousVolume", AudioPlayer_GetCurrentVolume()); +#endif SdCard_Exit(); Serial.flush(); @@ -222,20 +223,19 @@ void System_DeepSleepManager(void) { Power_PeripheralOff(); // time to settle down.. delay(200); - // .. for LPCD - #if defined (RFID_READER_TYPE_MFRC522_SPI) || defined (RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_PN5180) - Rfid_Exit(); - #endif - #ifdef PORT_EXPANDER_ENABLE - Port_Exit(); - #endif +// .. for LPCD +#if defined(RFID_READER_TYPE_MFRC522_SPI) || defined(RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_PN5180) + Rfid_Exit(); +#endif +#ifdef PORT_EXPANDER_ENABLE + Port_Exit(); +#endif // goto sleep now Log_Println("deep-sleep, good night.......", LOGLEVEL_NOTICE); esp_deep_sleep_start(); } } - // Print the wake-up reason why ESP32 is awake now void System_ShowWakeUpReason() { esp_sleep_wakeup_cause_t wakeup_reason; @@ -264,10 +264,10 @@ void System_ShowWakeUpReason() { } #ifdef ENABLE_ESPUINO_DEBUG - void System_esp_print_tasks(void) { - char *pbuffer = (char *)calloc(2048, 1); - vTaskGetRunTimeStats(pbuffer); - Serial.printf("=====\n%s\n=====", pbuffer); - free(pbuffer); - } +void System_esp_print_tasks(void) { + char *pbuffer = (char *) calloc(2048, 1); + vTaskGetRunTimeStats(pbuffer); + Serial.printf("=====\n%s\n=====", pbuffer); + free(pbuffer); +} #endif diff --git a/src/System.h b/src/System.h index ae67c8d9..25acb102 100644 --- a/src/System.h +++ b/src/System.h @@ -5,7 +5,6 @@ extern Preferences gPrefsRfid; extern Preferences gPrefsSettings; extern TaskHandle_t AudioTaskHandle; - void System_Init(void); void System_Cyclic(void); void System_UpdateActivityTimer(void); diff --git a/src/Web.cpp b/src/Web.cpp index 72deffef..694a3b94 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -1,20 +1,18 @@ #include -#include -#include -#include -#include -#include "soc/timer_group_struct.h" -#include "soc/timer_group_reg.h" -#include "freertos/ringbuf.h" -#include "ESPAsyncWebServer.h" -#include "AsyncJson.h" -#include "ArduinoJson.h" #include "settings.h" + +#include "Web.h" + +#include "ArduinoJson.h" +#include "AsyncJson.h" #include "AudioPlayer.h" #include "Battery.h" #include "Cmd.h" #include "Common.h" +#include "ESPAsyncWebServer.h" #include "Ftp.h" +#include "HTMLbinary.h" +#include "HallEffectSensor.h" #include "Led.h" #include "Log.h" #include "MemX.h" @@ -22,20 +20,22 @@ #include "Rfid.h" #include "SdCard.h" #include "System.h" -#include "Web.h" #include "Wlan.h" +#include "freertos/ringbuf.h" #include "revision.h" -#include "Rfid.h" -#include "HallEffectSensor.h" +#include "soc/timer_group_reg.h" +#include "soc/timer_group_struct.h" -#include "HTMLbinary.h" +#include +#include +#include +#include typedef struct { char nvsKey[13]; char nvsEntry[275]; } nvs_t; - AsyncWebServer wServer(80); AsyncWebSocket ws("/ws"); AsyncEventSource events("/events"); @@ -85,25 +85,24 @@ static void webserverStart(void); // If PSRAM is available use it allocate memory for JSON-objects struct SpiRamAllocator { - void* allocate(size_t size) { + void *allocate(size_t size) { return ps_malloc(size); - } - void deallocate(void* pointer) { + void deallocate(void *pointer) { free(pointer); } }; using SpiRamJsonDocument = BasicJsonDocument; -static void serveProgmemFiles(const String& uri, const String& contentType, const uint8_t *content, size_t len) { +static void serveProgmemFiles(const String &uri, const String &contentType, const uint8_t *content, size_t len) { wServer.on(uri.c_str(), HTTP_GET, [contentType, content, len](AsyncWebServerRequest *request) { AsyncWebServerResponse *response; // const bool etag = request->hasHeader("if-None-Match") && request->getHeader("if-None-Match")->value().equals(gitRevShort); const bool etag = false; - if (etag) + if (etag) { response = request->beginResponse(304); - else { + } else { response = request->beginResponse_P(200, contentType, content, len); response->addHeader("Content-Encoding", "gzip"); } @@ -113,67 +112,64 @@ static void serveProgmemFiles(const String& uri, const String& contentType, cons }); } +class OneParamRewrite : public AsyncWebRewrite { +protected: + String _urlPrefix; + int _paramIndex; + String _paramsBackup; -class OneParamRewrite : public AsyncWebRewrite -{ - protected: - String _urlPrefix; - int _paramIndex; - String _paramsBackup; - - public: - OneParamRewrite(const char* from, const char* to) - : AsyncWebRewrite(from, to) { - - _paramIndex = _from.indexOf('{'); - - if( _paramIndex >=0 && _from.endsWith("}")) { - _urlPrefix = _from.substring(0, _paramIndex); - int index = _params.indexOf('{'); - if(index >= 0) { - _params = _params.substring(0, index); - } - } else { - _urlPrefix = _from; - } - _paramsBackup = _params; - } - - bool match(AsyncWebServerRequest *request) override { - if(request->url().startsWith(_urlPrefix)) { - if(_paramIndex >= 0) { - _params = _paramsBackup + request->url().substring(_paramIndex); - } else { - _params = _paramsBackup; - } - return true; - - } else { - return false; - } - } -}; +public: + OneParamRewrite(const char *from, const char *to) + : AsyncWebRewrite(from, to) { + _paramIndex = _from.indexOf('{'); + + if (_paramIndex >= 0 && _from.endsWith("}")) { + _urlPrefix = _from.substring(0, _paramIndex); + int index = _params.indexOf('{'); + if (index >= 0) { + _params = _params.substring(0, index); + } + } else { + _urlPrefix = _from; + } + _paramsBackup = _params; + } + + bool match(AsyncWebServerRequest *request) override { + if (request->url().startsWith(_urlPrefix)) { + if (_paramIndex >= 0) { + _params = _paramsBackup + request->url().substring(_paramIndex); + } else { + _params = _paramsBackup; + } + return true; + + } else { + return false; + } + } +}; // List all key in NVS for a given namespace // callback function is called for every key with userdefined data object -bool listNVSKeys(const char *_namespace, void* data, bool (*callback)(const char * key, void* data)) { - Led_SetPause(true); // Workaround to prevent exceptions due to Neopixel-signalisation while NVS-write +bool listNVSKeys(const char *_namespace, void *data, bool (*callback)(const char *key, void *data)) { + Led_SetPause(true); // Workaround to prevent exceptions due to Neopixel-signalisation while NVS-write esp_partition_iterator_t pi; // Iterator for find - const esp_partition_t *nvs; // Pointer to partition struct + const esp_partition_t *nvs; // Pointer to partition struct esp_err_t result = ESP_OK; const char *partname = "nvs"; - uint8_t pagenr = 0; // Page number in NVS - uint8_t i; // Index in Entry 0..125 - uint8_t bm; // Bitmap for an entry - uint32_t offset = 0; // Offset in nvs partition + uint8_t pagenr = 0; // Page number in NVS + uint8_t i; // Index in Entry 0..125 + uint8_t bm; // Bitmap for an entry + uint32_t offset = 0; // Offset in nvs partition uint8_t namespace_ID; // Namespace ID found - pi = esp_partition_find(ESP_PARTITION_TYPE_DATA, // Get partition iterator for - ESP_PARTITION_SUBTYPE_ANY, // this partition - partname); + pi = esp_partition_find(ESP_PARTITION_TYPE_DATA, // Get partition iterator for + ESP_PARTITION_SUBTYPE_ANY, // this partition + partname); if (pi) { - nvs = esp_partition_get(pi); // Get partition struct + nvs = esp_partition_get(pi); // Get partition struct esp_partition_iterator_release(pi); // Release the iterator Log_Printf(LOGLEVEL_DEBUG, "Partition %s found, %d bytes", partname, nvs->size); } else { @@ -183,8 +179,8 @@ bool listNVSKeys(const char *_namespace, void* data, bool (*callback)(const char namespace_ID = FindNsID(nvs, _namespace); // Find ID of our namespace in NVS while (offset < nvs->size) { result = esp_partition_read(nvs, offset, // Read 1 page in nvs partition - &buf, - sizeof(nvs_page)); + &buf, + sizeof(nvs_page)); if (result != ESP_OK) { Log_Println("Error reading NVS!", LOGLEVEL_ERROR); return false; @@ -217,11 +213,11 @@ bool listNVSKeys(const char *_namespace, void* data, bool (*callback)(const char } // callback for writing a NVS entry to file -bool DumpNvsToSdCallback(const char * key, void* data) { +bool DumpNvsToSdCallback(const char *key, void *data) { String s = gPrefsRfid.getString(key); File *file = (File *) data; file->printf("%s%s%s%s\n", stringOuterDelimiter, key, stringOuterDelimiter, s.c_str()); - return true; + return true; } // Dumps all RFID-entries from NVS into a file on SD-card @@ -248,7 +244,7 @@ static void handleWiFiScanRequest(AsyncWebServerRequest *request) { if (n == -2) { // -2 if scan not triggered WiFi.scanNetworks(true, false, true, 120); - } else if(n) { + } else if (n) { for (int i = 0; i < n; ++i) { if (i > 9) { break; @@ -262,20 +258,22 @@ static void handleWiFiScanRequest(AsyncWebServerRequest *request) { } else { quality = 2 * (WiFi.RSSI(i) + 100); } - if (i) json += ","; + if (i) { + json += ","; + } json += "{"; json += "\"ssid\":\"" + WiFi.SSID(i) + "\""; json += ",\"bssid\":\"" + WiFi.BSSIDstr(i) + "\""; json += ",\"rssi\":" + String(WiFi.RSSI(i)); json += ",\"channel\":" + String(WiFi.channel(i)); json += ",\"secure\":" + String(WiFi.encryptionType(i)); - json += ",\"quality\":"+ String(quality); // WiFi strength in percent + json += ",\"quality\":" + String(quality); // WiFi strength in percent json += ",\"wico\":\"w" + String(int(round(map(quality, 0, 100, 1, 4)))) + "\""; // WiFi strength icon ("w1"-"w4") json += ",\"pico\":\"" + String((WIFI_AUTH_OPEN == WiFi.encryptionType(i)) ? "" : "pw") + "\""; // auth icon ("p1" for secured) json += "}"; } WiFi.scanDelete(); - if(WiFi.scanComplete() == -2) { + if (WiFi.scanComplete() == -2) { WiFi.scanNetworks(true, false, true, 120); } } @@ -309,25 +307,24 @@ void webserverStart(void) { // Default wServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response; // const bool etag = request->hasHeader("if-None-Match") && request->getHeader("if-None-Match")->value().equals(gitRevShort); const bool etag = false; - if (etag) + if (etag) { response = request->beginResponse(304); - else { + } else { if (WiFi.getMode() == WIFI_STA) { // serve management.html in station-mode - if (gFSystem.exists("/.html/index.htm")) + if (gFSystem.exists("/.html/index.htm")) { response = request->beginResponse(gFSystem, "/.html/index.htm", String(), false); - else { - response = request->beginResponse_P(200, "text/html", (const uint8_t *)management_BIN, sizeof(management_BIN)); + } else { + response = request->beginResponse_P(200, "text/html", (const uint8_t *) management_BIN, sizeof(management_BIN)); response->addHeader("Content-Encoding", "gzip"); - } + } } else { // serve accesspoint.html in AP-mode - response = request->beginResponse_P(200, "text/html", (const uint8_t *)accesspoint_BIN, sizeof(accesspoint_BIN)); + response = request->beginResponse_P(200, "text/html", (const uint8_t *) accesspoint_BIN, sizeof(accesspoint_BIN)); response->addHeader("Content-Encoding", "gzip"); } } @@ -357,25 +354,26 @@ void webserverStart(void) { // OTA-upload wServer.on( "/update", HTTP_POST, [](AsyncWebServerRequest *request) { - #ifdef BOARD_HAS_16MB_FLASH_AND_OTA_SUPPORT - if (Update.hasError()) { - request->send(500, "text/plain", Update.errorString()); - } else { - request->send(200, "text/html", restartWebsite); - } - #else - request->send(500, "text/html", otaNotSupportedWebsite); - #endif - }, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { - #ifndef BOARD_HAS_16MB_FLASH_AND_OTA_SUPPORT - Log_Println(otaNotSupported, LOGLEVEL_NOTICE); - return; - #endif +#ifdef BOARD_HAS_16MB_FLASH_AND_OTA_SUPPORT + if (Update.hasError()) { + request->send(500, "text/plain", Update.errorString()); + } else { + request->send(200, "text/html", restartWebsite); + } +#else + request->send(500, "text/html", otaNotSupportedWebsite); +#endif + }, + [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { +#ifndef BOARD_HAS_16MB_FLASH_AND_OTA_SUPPORT + Log_Println(otaNotSupported, LOGLEVEL_NOTICE); + return; +#endif if (!index) { // pause some tasks to get more free CPU time for the upload vTaskSuspend(AudioTaskHandle); - Led_TaskPause(); + Led_TaskPause(); Rfid_TaskPause(); Update.begin(); Log_Println(fwStart, LOGLEVEL_NOTICE); @@ -393,11 +391,11 @@ void webserverStart(void) { Log_Println(fwEnd, LOGLEVEL_NOTICE); if (Update.hasError()) { Log_Println(Update.errorString(), LOGLEVEL_ERROR); - } + } Serial.flush(); - //ESP.restart(); // restart is done via webpage javascript + // ESP.restart(); // restart is done via webpage javascript } - }); + }); // ESP-restart wServer.on("/restart", HTTP_POST, [](AsyncWebServerRequest *request) { @@ -411,15 +409,15 @@ void webserverStart(void) { System_RequestSleep(); }); - #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY +#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY // runtime task statistics - wServer.on("/stats", HTTP_GET, [](AsyncWebServerRequest *request){ + wServer.on("/stats", HTTP_GET, [](AsyncWebServerRequest *request) { AsyncResponseStream *response = request->beginResponseStream("text/html"); response->println(" ESPuino runtime stats"); response->println(""); // refresh page every 2 seconds response->println("Tasklist:
");
 			// show tasklist
-			char *pbuffer = (char *)calloc(2048, 1);
+			char *pbuffer = (char *) calloc(2048, 1);
 			vTaskList(pbuffer);
 			response->println(pbuffer);
 			response->println("


Runtime statistics:
");
@@ -428,34 +426,33 @@ void webserverStart(void) {
 			response->println(pbuffer);
 			response->println("
"); free(pbuffer); - //send the response last + // send the response last request->send(response); }); - #endif +#endif // erase all RFID-assignments from NVS wServer.on("/rfidnvserase", HTTP_POST, [](AsyncWebServerRequest *request) { Log_Println(eraseRfidNvs, LOGLEVEL_NOTICE); // make a backup first - Web_DumpNvsToSd("rfidTags", backupFile); + Web_DumpNvsToSd("rfidTags", backupFile); if (gPrefsRfid.clear()) { request->send(200); } else { request->send(500); } - System_UpdateActivityTimer(); + System_UpdateActivityTimer(); }); // RFID wServer.on("/rfid", HTTP_GET, handleGetRFIDRequest); wServer.addHandler(new AsyncCallbackJsonWebHandler("/rfid", handlePostRFIDRequest)); - wServer.addRewrite(new OneParamRewrite("/rfid/{id}", "/rfid?id={id}") ); + wServer.addRewrite(new OneParamRewrite("/rfid/{id}", "/rfid?id={id}")); wServer.on("/rfid", HTTP_DELETE, handleDeleteRFIDRequest); // WiFi scan wServer.on("/wifiscan", HTTP_GET, handleWiFiScanRequest); - // Fileexplorer (realtime) wServer.on("/explorer", HTTP_GET, explorerHandleListRequest); @@ -478,7 +475,7 @@ void webserverStart(void) { wServer.on("/savedSSIDs", HTTP_GET, handleGetSavedSSIDs); wServer.addHandler(new AsyncCallbackJsonWebHandler("/savedSSIDs", handlePostSavedSSIDs)); - wServer.addRewrite(new OneParamRewrite("/savedSSIDs/{ssid}", "/savedSSIDs?ssid={ssid}") ); + wServer.addRewrite(new OneParamRewrite("/savedSSIDs/{ssid}", "/savedSSIDs?ssid={ssid}")); wServer.on("/savedSSIDs", HTTP_DELETE, handleDeleteSavedSSIDs); wServer.on("/activeSSID", HTTP_GET, handleGetActiveSSID); @@ -511,17 +508,17 @@ void webserverStart(void) { }); // ESPuino settings wServer.on("/settings", HTTP_GET, handleGetSettings); - wServer.addHandler(new AsyncCallbackJsonWebHandler("/settings", handlePostSettings)); - // Init HallEffectSensor Value - #ifdef HALLEFFECT_SENSOR_ENABLE - wServer.on("/inithalleffectsensor", HTTP_GET, [](AsyncWebServerRequest *request) { - bool bres = gHallEffectSensor.saveActualFieldValue2NVS(); - char buffer[128]; - snprintf(buffer, sizeof(buffer), "WebRequest>HallEffectSensor FieldValue: %d => NVS, Status: %s", gHallEffectSensor.NullFieldValue(), bres ? "OK" : "ERROR"); - Log_Println(buffer, LOGLEVEL_INFO); - request->send(200, "text/html", buffer); - }); - #endif + wServer.addHandler(new AsyncCallbackJsonWebHandler("/settings", handlePostSettings)); + // Init HallEffectSensor Value +#ifdef HALLEFFECT_SENSOR_ENABLE + wServer.on("/inithalleffectsensor", HTTP_GET, [](AsyncWebServerRequest *request) { + bool bres = gHallEffectSensor.saveActualFieldValue2NVS(); + char buffer[128]; + snprintf(buffer, sizeof(buffer), "WebRequest>HallEffectSensor FieldValue: %d => NVS, Status: %s", gHallEffectSensor.NullFieldValue(), bres ? "OK" : "ERROR"); + Log_Println(buffer, LOGLEVEL_INFO); + request->send(200, "text/html", buffer); + }); +#endif wServer.onNotFound(notFound); @@ -541,60 +538,52 @@ unsigned long lastPongTimestamp; // process JSON to settings bool JSONToSettings(JsonObject doc) { - if (!doc) { + if (!doc) { Log_Println("JSONToSettings: doc unassigned", LOGLEVEL_DEBUG); return false; } if (doc.containsKey("general")) { // general settings - if (gPrefsSettings.putUInt("initVolume", doc["general"]["initVolume"].as()) == 0 || - gPrefsSettings.putUInt("maxVolumeSp", doc["general"]["maxVolumeSp"].as()) == 0 || - gPrefsSettings.putUInt("maxVolumeHp", doc["general"]["maxVolumeHp"].as()) == 0 || - gPrefsSettings.putUInt("mInactiviyT", doc["general"]["sleepInactivity"].as()) == 0 ) { - Log_Println("Failed to save general settings", LOGLEVEL_ERROR); - return false; - } + if (gPrefsSettings.putUInt("initVolume", doc["general"]["initVolume"].as()) == 0 || gPrefsSettings.putUInt("maxVolumeSp", doc["general"]["maxVolumeSp"].as()) == 0 || gPrefsSettings.putUInt("maxVolumeHp", doc["general"]["maxVolumeHp"].as()) == 0 || gPrefsSettings.putUInt("mInactiviyT", doc["general"]["sleepInactivity"].as()) == 0) { + Log_Println("Failed to save general settings", LOGLEVEL_ERROR); + return false; + } } if (doc.containsKey("wifi")) { // WiFi settings - static String hostName = doc["wifi"]["hostname"]; + static String hostName = doc["wifi"]["hostname"]; if (!Wlan_ValidateHostname(hostName)) { - Log_Println("Invalid hostname", LOGLEVEL_ERROR); - return false; + Log_Println("Invalid hostname", LOGLEVEL_ERROR); + return false; } if (((!Wlan_SetHostname(hostName)) || gPrefsSettings.putBool("ScanWiFiOnStart", doc["wifi"]["scanOnStart"].as()) == 0)) { - Log_Println("Failed to save wifi settings", LOGLEVEL_ERROR); - return false; + Log_Println("Failed to save wifi settings", LOGLEVEL_ERROR); + return false; } } if (doc.containsKey("led")) { // Neopixel settings - if (gPrefsSettings.putUChar("iLedBrightness", doc["led"]["initBrightness"].as()) == 0 || - gPrefsSettings.putUChar("nLedBrightness", doc["led"]["nightBrightness"].as()) == 0 ) { - Log_Println("Failed to save LED settings", LOGLEVEL_ERROR); - return false; + if (gPrefsSettings.putUChar("iLedBrightness", doc["led"]["initBrightness"].as()) == 0 || gPrefsSettings.putUChar("nLedBrightness", doc["led"]["nightBrightness"].as()) == 0) { + Log_Println("Failed to save LED settings", LOGLEVEL_ERROR); + return false; } } if (doc.containsKey("battery")) { // Battery settings - if (gPrefsSettings.putFloat("wLowVoltage", doc["battery"]["warnLowVoltage"].as()) == 0 || - gPrefsSettings.putFloat("vIndicatorLow", doc["battery"]["indicatorLow"].as()) == 0 || - gPrefsSettings.putFloat("vIndicatorHigh", doc["battery"]["indicatorHi"].as()) == 0 || - gPrefsSettings.putUInt("vCheckIntv", doc["battery"]["voltageCheckInterval"].as()) == 0 ) { - Log_Println("Failed to save battery settings", LOGLEVEL_ERROR); - return false; - } + if (gPrefsSettings.putFloat("wLowVoltage", doc["battery"]["warnLowVoltage"].as()) == 0 || gPrefsSettings.putFloat("vIndicatorLow", doc["battery"]["indicatorLow"].as()) == 0 || gPrefsSettings.putFloat("vIndicatorHigh", doc["battery"]["indicatorHi"].as()) == 0 || gPrefsSettings.putUInt("vCheckIntv", doc["battery"]["voltageCheckInterval"].as()) == 0) { + Log_Println("Failed to save battery settings", LOGLEVEL_ERROR); + return false; + } Battery_Init(); - } + } if (doc.containsKey("ftp")) { const char *_ftpUser = doc["ftp"]["username"]; const char *_ftpPwd = doc["ftp"]["password"]; - gPrefsSettings.putString("ftpuser", (String)_ftpUser); - gPrefsSettings.putString("ftppassword", (String)_ftpPwd); + gPrefsSettings.putString("ftpuser", (String) _ftpUser); + gPrefsSettings.putString("ftppassword", (String) _ftpPwd); // Check if settings were written successfully - if (!(String(_ftpUser).equals(gPrefsSettings.getString("ftpuser", "-1")) || - String(_ftpPwd).equals(gPrefsSettings.getString("ftppassword", "-1")))) { + if (!(String(_ftpUser).equals(gPrefsSettings.getString("ftpuser", "-1")) || String(_ftpPwd).equals(gPrefsSettings.getString("ftppassword", "-1")))) { Log_Println("Failed to save ftp settings", LOGLEVEL_ERROR); return false; } @@ -603,7 +592,7 @@ bool JSONToSettings(JsonObject doc) { if (_ftpStart == 1) { // ifdef FTP_ENABLE is checked in Ftp_EnableServer() Ftp_EnableServer(); } - } + } if (doc.containsKey("mqtt")) { uint8_t _mqttEnable = doc["mqtt"]["enable"].as(); const char *_mqttClientId = doc["mqtt"]["clientID"]; @@ -613,29 +602,27 @@ bool JSONToSettings(JsonObject doc) { uint16_t _mqttPort = doc["mqtt"]["port"].as(); gPrefsSettings.putUChar("enableMQTT", _mqttEnable); - gPrefsSettings.putString("mqttClientId", (String)_mqttClientId); - gPrefsSettings.putString("mqttServer", (String)_mqttServer); - gPrefsSettings.putString("mqttUser", (String)_mqttUser); - gPrefsSettings.putString("mqttPassword", (String)_mqttPwd); + gPrefsSettings.putString("mqttClientId", (String) _mqttClientId); + gPrefsSettings.putString("mqttServer", (String) _mqttServer); + gPrefsSettings.putString("mqttUser", (String) _mqttUser); + gPrefsSettings.putString("mqttPassword", (String) _mqttPwd); gPrefsSettings.putUInt("mqttPort", _mqttPort); - if ((gPrefsSettings.getUChar("enableMQTT", 99) != _mqttEnable) || - (!String(_mqttServer).equals(gPrefsSettings.getString("mqttServer", "-1")))) { + if ((gPrefsSettings.getUChar("enableMQTT", 99) != _mqttEnable) || (!String(_mqttServer).equals(gPrefsSettings.getString("mqttServer", "-1")))) { Log_Println("Failed to save mqtt settings", LOGLEVEL_ERROR); return false; } - } + } if (doc.containsKey("bluetooth")) { // bluetooth settings const char *_btDeviceName = doc["bluetooth"]["deviceName"]; - gPrefsSettings.putString("btDeviceName", (String)_btDeviceName); + gPrefsSettings.putString("btDeviceName", (String) _btDeviceName); const char *btPinCode = doc["bluetooth"]["pinCode"]; - gPrefsSettings.putString("btPinCode", (String)btPinCode); + gPrefsSettings.putString("btPinCode", (String) btPinCode); // Check if settings were written successfully - if (gPrefsSettings.getString("btDeviceName", "") != _btDeviceName || - gPrefsSettings.getString("btPinCode", "") != btPinCode) { - Log_Println("Failed to save bluetooth settings", LOGLEVEL_ERROR); - return false; + if (gPrefsSettings.getString("btDeviceName", "") != _btDeviceName || gPrefsSettings.getString("btPinCode", "") != btPinCode) { + Log_Println("Failed to save bluetooth settings", LOGLEVEL_ERROR); + return false; } } else if (doc.containsKey("rfidMod")) { const char *_rfidIdModId = doc["rfidMod"]["rfidIdMod"]; @@ -665,9 +652,9 @@ bool JSONToSettings(JsonObject doc) { char rfidString[275]; snprintf(rfidString, sizeof(rfidString) / sizeof(rfidString[0]), "%s%s%s0%s%u%s0", stringDelimiter, _fileOrUrlAscii, stringDelimiter, stringDelimiter, _playMode, stringDelimiter); gPrefsRfid.putString(_rfidIdAssinId, rfidString); - #ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE - Rfid_ResetOldRfid(); // Set old rfid-id to crap in order to allow to re-apply a new assigned rfid-tag exactly once - #endif +#ifdef DONT_ACCEPT_SAME_RFID_TWICE_ENABLE + Rfid_ResetOldRfid(); // Set old rfid-id to crap in order to allow to re-apply a new assigned rfid-tag exactly once +#endif String s = gPrefsRfid.getString(_rfidIdAssinId, "-1"); if (s.compareTo(rfidString)) { @@ -685,7 +672,8 @@ bool JSONToSettings(JsonObject doc) { if (doc["controls"].containsKey("set_volume")) { uint8_t new_vol = doc["controls"]["set_volume"].as(); AudioPlayer_VolumeToQueueSender(new_vol, true); - } if (doc["controls"].containsKey("action")) { + } + if (doc["controls"].containsKey("action")) { uint8_t cmd = doc["controls"]["action"].as(); Cmd_Action(cmd); } @@ -730,7 +718,7 @@ static void settingsToJSON(JsonObject obj, String section) { // saved SSID's JsonObject ssidsObj = obj.createNestedObject("ssids"); static String ssids[10]; - + JsonArray ssidArr = ssidsObj.createNestedArray("savedSSIDs"); size_t len = Wlan_GetSSIDs(ssids, 10); if (len > 0) { @@ -743,84 +731,84 @@ static void settingsToJSON(JsonObject obj, String section) { ssidsObj["active"] = Wlan_GetCurrentSSID(); } } - #ifdef NEOPIXEL_ENABLE - if ((section == "") || (section == "led")) { - // LED settings - JsonObject ledObj = obj.createNestedObject("led"); - ledObj["initBrightness"].set(gPrefsSettings.getUChar("iLedBrightness", 0)); - ledObj["nightBrightness"].set(gPrefsSettings.getUChar("nLedBrightness", 0)); - } - #endif - #ifdef MEASURE_BATTERY_VOLTAGE - if ((section == "") || (section == "battery")) { - // battery settings - JsonObject batteryObj = obj.createNestedObject("battery"); - batteryObj["warnLowVoltage"].set(gPrefsSettings.getFloat("wLowVoltage", s_warningLowVoltage)); - batteryObj["indicatorLow"].set(gPrefsSettings.getFloat("vIndicatorLow", s_voltageIndicatorLow)); - batteryObj["indicatorHi"].set(gPrefsSettings.getFloat("vIndicatorHigh", s_voltageIndicatorHigh)); - batteryObj["voltageCheckInterval"].set(gPrefsSettings.getUInt("vCheckIntv", s_batteryCheckInterval)); - } - #endif +#ifdef NEOPIXEL_ENABLE + if ((section == "") || (section == "led")) { + // LED settings + JsonObject ledObj = obj.createNestedObject("led"); + ledObj["initBrightness"].set(gPrefsSettings.getUChar("iLedBrightness", 0)); + ledObj["nightBrightness"].set(gPrefsSettings.getUChar("nLedBrightness", 0)); + } +#endif +#ifdef MEASURE_BATTERY_VOLTAGE + if ((section == "") || (section == "battery")) { + // battery settings + JsonObject batteryObj = obj.createNestedObject("battery"); + batteryObj["warnLowVoltage"].set(gPrefsSettings.getFloat("wLowVoltage", s_warningLowVoltage)); + batteryObj["indicatorLow"].set(gPrefsSettings.getFloat("vIndicatorLow", s_voltageIndicatorLow)); + batteryObj["indicatorHi"].set(gPrefsSettings.getFloat("vIndicatorHigh", s_voltageIndicatorHigh)); + batteryObj["voltageCheckInterval"].set(gPrefsSettings.getUInt("vCheckIntv", s_batteryCheckInterval)); + } +#endif if (section == "defaults") { // default factory settings JsonObject defaultsObj = obj.createNestedObject("defaults"); - defaultsObj["initVolume"].set(3u); // AUDIOPLAYER_VOLUME_INIT - defaultsObj["maxVolumeSp"].set(21u); // AUDIOPLAYER_VOLUME_MAX - defaultsObj["maxVolumeHp"].set(18u); // gPrefsSettings.getUInt("maxVolumeHp", 0)); - defaultsObj["sleepInactivity"].set(10u); // System_MaxInactivityTime - #ifdef NEOPIXEL_ENABLE - defaultsObj["initBrightness"].set(16u); // LED_INITIAL_BRIGHTNESS - defaultsObj["nightBrightness"].set(2u); // LED_INITIAL_NIGHT_BRIGHTNESS - #endif - #ifdef MEASURE_BATTERY_VOLTAGE - defaultsObj["warnLowVoltage"].set(s_warningLowVoltage); - defaultsObj["indicatorLow"].set(s_voltageIndicatorLow); - defaultsObj["indicatorHi"].set(s_voltageIndicatorHigh); - defaultsObj["voltageCheckInterval"].set(s_batteryCheckInterval); - #endif - } - // FTP - #ifdef FTP_ENABLE - if ((section == "") || (section == "ftp")) { - JsonObject ftpObj = obj.createNestedObject("ftp"); - ftpObj["username"] = gPrefsSettings.getString("ftpuser", "-1"); - ftpObj["password"] = gPrefsSettings.getString("ftppassword", "-1"); - ftpObj["maxUserLength"].set(ftpUserLength - 1); - ftpObj["maxPwdLength"].set(ftpUserLength - 1); - } - #endif - // MQTT - #ifdef MQTT_ENABLE - if ((section == "") || (section == "mqtt")) { - JsonObject mqttObj = obj.createNestedObject("mqtt"); - mqttObj["enable"].set(Mqtt_IsEnabled()); - mqttObj["clientID"] = gPrefsSettings.getString("mqttClientId", "-1"); - mqttObj["server"] = gPrefsSettings.getString("mqttServer", "-1"); - mqttObj["port"].set(gPrefsSettings.getUInt("mqttPort", 0)); - mqttObj["username"] = gPrefsSettings.getString("mqttUser", "-1"); - mqttObj["password"] = gPrefsSettings.getString("mqttPassword", "-1"); - mqttObj["maxUserLength"].set(mqttUserLength - 1); - mqttObj["maxPwdLength"].set(mqttPasswordLength - 1); - mqttObj["maxClientIdLength"].set(mqttClientIdLength - 1); - mqttObj["maxServerLength"].set(mqttServerLength - 1); + defaultsObj["initVolume"].set(3u); // AUDIOPLAYER_VOLUME_INIT + defaultsObj["maxVolumeSp"].set(21u); // AUDIOPLAYER_VOLUME_MAX + defaultsObj["maxVolumeHp"].set(18u); // gPrefsSettings.getUInt("maxVolumeHp", 0)); + defaultsObj["sleepInactivity"].set(10u); // System_MaxInactivityTime +#ifdef NEOPIXEL_ENABLE + defaultsObj["initBrightness"].set(16u); // LED_INITIAL_BRIGHTNESS + defaultsObj["nightBrightness"].set(2u); // LED_INITIAL_NIGHT_BRIGHTNESS +#endif +#ifdef MEASURE_BATTERY_VOLTAGE + defaultsObj["warnLowVoltage"].set(s_warningLowVoltage); + defaultsObj["indicatorLow"].set(s_voltageIndicatorLow); + defaultsObj["indicatorHi"].set(s_voltageIndicatorHigh); + defaultsObj["voltageCheckInterval"].set(s_batteryCheckInterval); +#endif + } +// FTP +#ifdef FTP_ENABLE + if ((section == "") || (section == "ftp")) { + JsonObject ftpObj = obj.createNestedObject("ftp"); + ftpObj["username"] = gPrefsSettings.getString("ftpuser", "-1"); + ftpObj["password"] = gPrefsSettings.getString("ftppassword", "-1"); + ftpObj["maxUserLength"].set(ftpUserLength - 1); + ftpObj["maxPwdLength"].set(ftpUserLength - 1); + } +#endif +// MQTT +#ifdef MQTT_ENABLE + if ((section == "") || (section == "mqtt")) { + JsonObject mqttObj = obj.createNestedObject("mqtt"); + mqttObj["enable"].set(Mqtt_IsEnabled()); + mqttObj["clientID"] = gPrefsSettings.getString("mqttClientId", "-1"); + mqttObj["server"] = gPrefsSettings.getString("mqttServer", "-1"); + mqttObj["port"].set(gPrefsSettings.getUInt("mqttPort", 0)); + mqttObj["username"] = gPrefsSettings.getString("mqttUser", "-1"); + mqttObj["password"] = gPrefsSettings.getString("mqttPassword", "-1"); + mqttObj["maxUserLength"].set(mqttUserLength - 1); + mqttObj["maxPwdLength"].set(mqttPasswordLength - 1); + mqttObj["maxClientIdLength"].set(mqttClientIdLength - 1); + mqttObj["maxServerLength"].set(mqttServerLength - 1); + } +#endif +// Bluetooth +#ifdef BLUETOOTH_ENABLE + if ((section == "") || (section == "bluetooth")) { + JsonObject btObj = obj.createNestedObject("bluetooth"); + if (gPrefsSettings.isKey("btDeviceName")) { + btObj["deviceName"] = gPrefsSettings.getString("btDeviceName", ""); + } else { + btObj["deviceName"] = ""; } - #endif - // Bluetooth - #ifdef BLUETOOTH_ENABLE - if ((section == "") || (section == "bluetooth")) { - JsonObject btObj = obj.createNestedObject("bluetooth"); - if (gPrefsSettings.isKey("btDeviceName")) { - btObj["deviceName"] = gPrefsSettings.getString("btDeviceName", ""); - } else { - btObj["deviceName"] = ""; - } - if (gPrefsSettings.isKey("btPinCode")) { - btObj["pinCode"] = gPrefsSettings.getString("btPinCode", ""); - } else { - btObj["pinCode"] = ""; - } + if (gPrefsSettings.isKey("btPinCode")) { + btObj["pinCode"] = gPrefsSettings.getString("btPinCode", ""); + } else { + btObj["pinCode"] = ""; } - #endif + } +#endif } // handle get info @@ -831,11 +819,11 @@ void handleGetInfo(AsyncWebServerRequest *request) { if (request->hasParam("section")) { section = request->getParam("section")->value(); } - #ifdef BOARD_HAS_PSRAM - SpiRamJsonDocument doc(512); - #else - StaticJsonDocument<512> doc; - #endif +#ifdef BOARD_HAS_PSRAM + SpiRamJsonDocument doc(512); +#else + StaticJsonDocument<512> doc; +#endif JsonObject infoObj = doc.createNestedObject("info"); // software if ((section == "") || (section == "software")) { @@ -856,7 +844,7 @@ void handleGetInfo(AsyncWebServerRequest *request) { if ((section == "") || (section == "memory")) { JsonObject memoryObj = infoObj.createNestedObject("memory"); memoryObj["freeHeap"] = ESP.getFreeHeap(); - memoryObj["largestFreeBlock"] = (uint32_t)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + memoryObj["largestFreeBlock"] = (uint32_t) heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); if (psramInit()) { memoryObj["freePSRam"] = ESP.getFreePsram(); } @@ -865,37 +853,37 @@ void handleGetInfo(AsyncWebServerRequest *request) { if ((section == "") || (section == "wifi")) { JsonObject wifiObj = infoObj.createNestedObject("wifi"); wifiObj["ip"] = Wlan_GetIpAddress(); - wifiObj["rssi"] = (int8_t)Wlan_GetRssi(); + wifiObj["rssi"] = (int8_t) Wlan_GetRssi(); } // audio if ((section == "") || (section == "audio")) { JsonObject audioObj = infoObj.createNestedObject("audio"); audioObj["playtimeTotal"] = AudioPlayer_GetPlayTimeAllTime(); audioObj["playtimeSinceStart"] = AudioPlayer_GetPlayTimeSinceStart(); - audioObj["firstStart"] = gPrefsSettings.getULong("firstStart", 0); - } - #ifdef BATTERY_MEASURE_ENABLE - // battery - if ((section == "") || (section == "battery")) { - JsonObject batteryObj = infoObj.createNestedObject("battery"); - batteryObj["currVoltage"] = Battery_GetVoltage(); - batteryObj["chargeLevel"] = Battery_EstimateLevel() * 100; - } - #endif - #ifdef HALLEFFECT_SENSOR_ENABLE - if ((section == "") || (section == "hallsensor")) { - // hallsensor - JsonObject hallObj = infoObj.createNestedObject("hallsensor"); - uint16_t sva = gHallEffectSensor.readSensorValueAverage(true); - int diff = sva-gHallEffectSensor.NullFieldValue(); - - hallObj["nullFieldValue"] =gHallEffectSensor.NullFieldValue(); - hallObj["actual"] = sva; - hallObj["diff"] = diff; - hallObj["lastWaitState"] = gHallEffectSensor.LastWaitForState(); - hallObj["lastWaitMS"] = gHallEffectSensor.LastWaitForStateMS(); - } - #endif + audioObj["firstStart"] = gPrefsSettings.getULong("firstStart", 0); + } +#ifdef BATTERY_MEASURE_ENABLE + // battery + if ((section == "") || (section == "battery")) { + JsonObject batteryObj = infoObj.createNestedObject("battery"); + batteryObj["currVoltage"] = Battery_GetVoltage(); + batteryObj["chargeLevel"] = Battery_EstimateLevel() * 100; + } +#endif +#ifdef HALLEFFECT_SENSOR_ENABLE + if ((section == "") || (section == "hallsensor")) { + // hallsensor + JsonObject hallObj = infoObj.createNestedObject("hallsensor"); + uint16_t sva = gHallEffectSensor.readSensorValueAverage(true); + int diff = sva - gHallEffectSensor.NullFieldValue(); + + hallObj["nullFieldValue"] = gHallEffectSensor.NullFieldValue(); + hallObj["actual"] = sva; + hallObj["diff"] = diff; + hallObj["lastWaitState"] = gHallEffectSensor.LastWaitForState(); + hallObj["lastWaitMS"] = gHallEffectSensor.LastWaitForStateMS(); + } +#endif String serializedJsonString; serializeJson(infoObj, serializedJsonString); @@ -903,8 +891,6 @@ void handleGetInfo(AsyncWebServerRequest *request) { System_UpdateActivityTimer(); } - - // handle get settings void handleGetSettings(AsyncWebServerRequest *request) { @@ -913,11 +899,11 @@ void handleGetSettings(AsyncWebServerRequest *request) { if (request->hasParam("section")) { section = request->getParam("section")->value(); } - #ifdef BOARD_HAS_PSRAM - SpiRamJsonDocument doc(8192); - #else - StaticJsonDocument<8192> doc; - #endif +#ifdef BOARD_HAS_PSRAM + SpiRamJsonDocument doc(8192); +#else + StaticJsonDocument<8192> doc; +#endif JsonObject settingsObj = doc.createNestedObject("settings"); settingsToJSON(settingsObj, section); String serializedJsonString; @@ -927,7 +913,7 @@ void handleGetSettings(AsyncWebServerRequest *request) { // handle post settings void handlePostSettings(AsyncWebServerRequest *request, JsonVariant &json) { - const JsonObject& jsonObj = json.as(); + const JsonObject &jsonObj = json.as(); bool succ = JSONToSettings(jsonObj); if (succ) { request->send(200); @@ -936,19 +922,17 @@ void handlePostSettings(AsyncWebServerRequest *request, JsonVariant &json) { } } - - // Takes inputs from webgui, parses JSON and saves values in NVS // If operation was successful (NVS-write is verified) true is returned bool processJsonRequest(char *_serialJson) { - if (!_serialJson) { + if (!_serialJson) { return false; } - #ifdef BOARD_HAS_PSRAM - SpiRamJsonDocument doc(1000); - #else - StaticJsonDocument<1000> doc; - #endif +#ifdef BOARD_HAS_PSRAM + SpiRamJsonDocument doc(1000); +#else + StaticJsonDocument<1000> doc; +#endif DeserializationError error = deserializeJson(doc, _serialJson); @@ -961,11 +945,11 @@ bool processJsonRequest(char *_serialJson) { return JSONToSettings(obj); } - // Sends JSON-answers via websocket void Web_SendWebsocketData(uint32_t client, uint8_t code) { - if (!webserverStarted) + if (!webserverStarted) { return; + } char *jBuf = (char *) x_calloc(1024, sizeof(char)); StaticJsonDocument<1024> doc; JsonObject object = doc.to(); @@ -980,7 +964,7 @@ void Web_SendWebsocketData(uint32_t client, uint8_t code) { object["pong"] = "pong"; object["rssi"] = Wlan_GetRssi(); // todo: battery percent + loading status +++ - //object["battery"] = Battery_GetVoltage(); + // object["battery"] = Battery_GetVoltage(); } else if (code == 30) { JsonObject entry = object.createNestedObject("trackinfo"); entry["pausePlay"] = gPlayProperties.pausePlay; @@ -1000,7 +984,6 @@ void Web_SendWebsocketData(uint32_t client, uint8_t code) { settingsToJSON(entry, "ssids"); }; - serializeJson(doc, jBuf, 1024); if (client == 0) { @@ -1011,63 +994,62 @@ void Web_SendWebsocketData(uint32_t client, uint8_t code) { free(jBuf); } - // Processes websocket-requests void onWebsocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { if (type == WS_EVT_CONNECT) { - //client connected + // client connected Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] connect", server->url(), client->id()); - //client->printf("Hello Client %u :)", client->id()); - //client->ping(); + // client->printf("Hello Client %u :)", client->id()); + // client->ping(); } else if (type == WS_EVT_DISCONNECT) { - //client disconnected + // client disconnected Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] disconnect", server->url(), client->id()); } else if (type == WS_EVT_ERROR) { - //error was received from the other end - Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] error(%u): %s", server->url(), client->id(), *((uint16_t *)arg), (char *)data); + // error was received from the other end + Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] error(%u): %s", server->url(), client->id(), *((uint16_t *) arg), (char *) data); } else if (type == WS_EVT_PONG) { - //pong message was received (in response to a ping request maybe) - Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] pong[%u]: %s", server->url(), client->id(), len, (len) ? (char *)data : ""); + // pong message was received (in response to a ping request maybe) + Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] pong[%u]: %s", server->url(), client->id(), len, (len) ? (char *) data : ""); } else if (type == WS_EVT_DATA) { - //data packet - const AwsFrameInfo *info = (AwsFrameInfo *)arg; + // data packet + const AwsFrameInfo *info = (AwsFrameInfo *) arg; if (info && info->final && info->index == 0 && info->len == len && client && len > 0) { - //the whole message is in a single frame and we got all of it's data - //Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len); + // the whole message is in a single frame and we got all of it's data + // Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len); - if (processJsonRequest((char *)data)) { - if (data && (strncmp((char *)data, "getTrack", 8))) { // Don't send back ok-feedback if track's name is requested in background + if (processJsonRequest((char *) data)) { + if (data && (strncmp((char *) data, "getTrack", 8))) { // Don't send back ok-feedback if track's name is requested in background Web_SendWebsocketData(client->id(), 1); } } if (info->opcode == WS_TEXT) { data[len] = 0; - //Serial.printf("%s\n", (char *)data); + // Serial.printf("%s\n", (char *)data); } else { for (size_t i = 0; i < info->len; i++) { Serial.printf("%02x ", data[i]); } - //Serial.printf("\n"); + // Serial.printf("\n"); } } } } -void explorerCreateParentDirectories(const char* filePath) { +void explorerCreateParentDirectories(const char *filePath) { char tmpPath[MAX_FILEPATH_LENTGH]; char *rest; rest = strchr(filePath, '/'); while (rest) { - if (rest-filePath != 0){ - memcpy(tmpPath, filePath, rest-filePath); - tmpPath[rest-filePath] = '\0'; + if (rest - filePath != 0) { + memcpy(tmpPath, filePath, rest - filePath); + tmpPath[rest - filePath] = '\0'; Log_Printf(LOGLEVEL_DEBUG, "creating dir \"%s\"\n", tmpPath); gFSystem.mkdir(tmpPath); } - rest = strchr(rest+1, '/'); + rest = strchr(rest + 1, '/'); } } @@ -1103,7 +1085,7 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s // reset buffers index_buffer_write = 0; index_buffer_read = 0; - for (uint32_t i = 0; i < nr_of_buffers; i++){ + for (uint32_t i = 0; i < nr_of_buffers; i++) { size_in_buffer[i] = 0; buffer_full[i] = false; } @@ -1111,32 +1093,32 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s // Create Task for handling the storage of the data xTaskCreatePinnedToCore( explorerHandleFileStorageTask, /* Function to implement the task */ - "fileStorageTask", /* Name of the task */ - 4000, /* Stack size in words */ - filePath, /* Task input parameter */ - 2 | portPRIVILEGE_BIT, /* Priority of the task */ - &fileStorageTaskHandle, /* Task handle. */ - 1 /* Core where the task should run */ + "fileStorageTask", /* Name of the task */ + 4000, /* Stack size in words */ + filePath, /* Task input parameter */ + 2 | portPRIVILEGE_BIT, /* Priority of the task */ + &fileStorageTaskHandle, /* Task handle. */ + 1 /* Core where the task should run */ ); } if (len) { // wait till buffer is ready - while (buffer_full[index_buffer_write]){ - vTaskDelay(2u); + while (buffer_full[index_buffer_write]) { + vTaskDelay(2u); } size_t len_to_write = len; size_t space_left = chunk_size - size_in_buffer[index_buffer_write]; - if (space_left < len_to_write){ + if (space_left < len_to_write) { len_to_write = space_left; } // write content to buffer - memcpy(buffer[index_buffer_write]+size_in_buffer[index_buffer_write], data, len_to_write); + memcpy(buffer[index_buffer_write] + size_in_buffer[index_buffer_write], data, len_to_write); size_in_buffer[index_buffer_write] += len_to_write; // check if buffer is filled. If full, signal that ready and change buffers - if (size_in_buffer[index_buffer_write] == chunk_size){ + if (size_in_buffer[index_buffer_write] == chunk_size) { // signal, that buffer is ready. Increment index buffer_full[index_buffer_write] = true; index_buffer_write = (index_buffer_write + 1) % nr_of_buffers; @@ -1144,14 +1126,14 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s // if still content left, put it into next buffer if (len_to_write < len) { // wait till new buffer is ready - while (buffer_full[index_buffer_write]){ + while (buffer_full[index_buffer_write]) { vTaskDelay(2u); } - size_t len_left_to_write = len-len_to_write; + size_t len_left_to_write = len - len_to_write; memcpy(buffer[index_buffer_write], data + len_to_write, len_left_to_write); size_in_buffer[index_buffer_write] = len_left_to_write; } - } + } } if (final) { @@ -1169,19 +1151,19 @@ void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, s // feed the watchdog timer without delay void feedTheDog(void) { - #if defined(SD_MMC_1BIT_MODE) && defined(CONFIG_IDF_TARGET_ESP32) - // feed dog 0 - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; // write enable - TIMERG0.wdt_feed=1; // feed dog - TIMERG0.wdt_wprotect=0; // write protect - // feed dog 1 - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; // write enable - TIMERG1.wdt_feed=1; // feed dog - TIMERG1.wdt_wprotect=0; // write protect - #else +#if defined(SD_MMC_1BIT_MODE) && defined(CONFIG_IDF_TARGET_ESP32) + // feed dog 0 + TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; // write enable + TIMERG0.wdt_feed = 1; // feed dog + TIMERG0.wdt_wprotect = 0; // write protect + // feed dog 1 + TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE; // write enable + TIMERG1.wdt_feed = 1; // feed dog + TIMERG1.wdt_wprotect = 0; // write protect +#else // Without delay upload-feature is broken for SD via SPI (for whatever reason...) - vTaskDelay(portTICK_PERIOD_MS * 11); - #endif + vTaskDelay(portTICK_PERIOD_MS * 11); +#endif } void explorerHandleFileStorageTask(void *parameter) { @@ -1192,17 +1174,16 @@ void explorerHandleFileStorageTask(void *parameter) { uint32_t transferStartTimestamp = millis(); uint8_t value = 0; uint32_t lastUpdateTimestamp = millis(); - uint32_t maxUploadDelay = 20; // After this delay (in seconds) task will be deleted as transfer is considered to be finally broken + uint32_t maxUploadDelay = 20; // After this delay (in seconds) task will be deleted as transfer is considered to be finally broken BaseType_t uploadFileNotification; uint32_t uploadFileNotificationValue; - uploadFile = gFSystem.open((char *)parameter, "w"); + uploadFile = gFSystem.open((char *) parameter, "w"); uploadFile.setBufferSize(chunk_size); - // pause some tasks to get more free CPU time for the upload vTaskSuspend(AudioTaskHandle); - Led_TaskPause(); + Led_TaskPause(); Rfid_TaskPause(); for (;;) { @@ -1210,7 +1191,7 @@ void explorerHandleFileStorageTask(void *parameter) { uploadFileNotification = xTaskNotifyWait(0, 0, &uploadFileNotificationValue, 0); if ((buffer_full[index_buffer_read]) || (uploadFileNotification == pdPASS)) { - while (buffer_full[index_buffer_read]){ + while (buffer_full[index_buffer_read]) { chunkCount++; size_t item_size = size_in_buffer[index_buffer_read]; if (!uploadFile.write(buffer[index_buffer_read], item_size)) { @@ -1229,7 +1210,7 @@ void explorerHandleFileStorageTask(void *parameter) { if (uploadFileNotification == pdPASS) { uploadFile.close(); - Log_Printf(LOGLEVEL_INFO, fileWritten, (char *)parameter, bytesNok+bytesOk, (millis() - transferStartTimestamp), (bytesNok+bytesOk)/(millis() - transferStartTimestamp)); + Log_Printf(LOGLEVEL_INFO, fileWritten, (char *) parameter, bytesNok + bytesOk, (millis() - transferStartTimestamp), (bytesNok + bytesOk) / (millis() - transferStartTimestamp)); Log_Printf(LOGLEVEL_DEBUG, "Bytes [ok] %zu / [not ok] %zu, Chunks: %zu\n", bytesOk, bytesNok, chunkCount); // done exit loop to terminate break; @@ -1258,15 +1239,14 @@ void explorerHandleFileStorageTask(void *parameter) { vTaskDelete(NULL); } - // Sends a list of the content of a directory as JSON file // requires a GET parameter path for the directory void explorerHandleListRequest(AsyncWebServerRequest *request) { - #ifdef BOARD_HAS_PSRAM - SpiRamJsonDocument jsonBuffer(65636); - #else - StaticJsonDocument<8192> jsonBuffer; - #endif +#ifdef BOARD_HAS_PSRAM + SpiRamJsonDocument jsonBuffer(65636); +#else + StaticJsonDocument<8192> jsonBuffer; +#endif String serializedJsonString; char filePath[MAX_FILEPATH_LENTGH]; @@ -1295,7 +1275,7 @@ void explorerHandleListRequest(AsyncWebServerRequest *request) { String MyfileName = root.getNextFileName(&isDir); while (MyfileName != "") { // ignore hidden folders, e.g. MacOS spotlight files - if (!startsWith( MyfileName.c_str() , (char *)"/.")) { + if (!startsWith(MyfileName.c_str(), (char *) "/.")) { JsonObject entry = obj.createNestedObject(); convertAsciiToUtf8(MyfileName.c_str(), filePath); std::string path = filePath; @@ -1368,10 +1348,10 @@ void explorerHandleDownloadRequest(AsyncWebServerRequest *request) { }; fileBlk *fileObj = new fileBlk; fileObj->dataFile = file; - request->_tempObject = (void*)fileObj; + request->_tempObject = (void *) fileObj; AsyncWebServerResponse *response = request->beginResponse(dataType, fileObj->dataFile.size(), [request](uint8_t *buffer, size_t maxlen, size_t index) -> size_t { - fileBlk *fileObj = (fileBlk*)request->_tempObject; + fileBlk *fileObj = (fileBlk *) request->_tempObject; size_t thisSize = fileObj->dataFile.read(buffer, maxlen); if ((index + thisSize) >= fileObj->dataFile.size()) { fileObj->dataFile.close(); @@ -1508,32 +1488,32 @@ void handleGetSavedSSIDs(AsyncWebServerRequest *request) { } void handlePostSavedSSIDs(AsyncWebServerRequest *request, JsonVariant &json) { - const JsonObject& jsonObj = json.as(); + const JsonObject &jsonObj = json.as(); struct WiFiSettings networkSettings; // TODO: we truncate ssid and password, which is better than not checking at all, but still silently failing - strncpy(networkSettings.ssid, (const char*) jsonObj["ssid"], 32); + strncpy(networkSettings.ssid, (const char *) jsonObj["ssid"], 32); networkSettings.ssid[32] = '\0'; - strncpy(networkSettings.password, (const char*) jsonObj["pwd"], 64); + strncpy(networkSettings.password, (const char *) jsonObj["pwd"], 64); networkSettings.password[64] = '\0'; networkSettings.use_static_ip = (bool) jsonObj["static"]; if (jsonObj.containsKey("static_addr")) { - networkSettings.static_addr = (uint32_t) IPAddress().fromString((const char*) jsonObj["static_addr"]); + networkSettings.static_addr = (uint32_t) IPAddress().fromString((const char *) jsonObj["static_addr"]); } if (jsonObj.containsKey("static_gateway")) { - networkSettings.static_gateway = (uint32_t) IPAddress().fromString((const char*) jsonObj["static_gateway"]); + networkSettings.static_gateway = (uint32_t) IPAddress().fromString((const char *) jsonObj["static_gateway"]); } if (jsonObj.containsKey("static_subnet")) { - networkSettings.static_subnet = (uint32_t) IPAddress().fromString((const char*) jsonObj["static_subnet"]); + networkSettings.static_subnet = (uint32_t) IPAddress().fromString((const char *) jsonObj["static_subnet"]); } if (jsonObj.containsKey("static_dns1")) { - networkSettings.static_dns1 = (uint32_t) IPAddress().fromString((const char*) jsonObj["static_dns1"]); + networkSettings.static_dns1 = (uint32_t) IPAddress().fromString((const char *) jsonObj["static_dns1"]); } if (jsonObj.containsKey("static_dns2")) { - networkSettings.static_dns2 = (uint32_t) IPAddress().fromString((const char*) jsonObj["static_dns2"]); + networkSettings.static_dns2 = (uint32_t) IPAddress().fromString((const char *) jsonObj["static_dns2"]); } bool succ = Wlan_AddNetworkSettings(networkSettings); @@ -1542,11 +1522,11 @@ void handlePostSavedSSIDs(AsyncWebServerRequest *request, JsonVariant &json) { request->send(200, "text/plain; charset=utf-8", networkSettings.ssid); } else { request->send(500, "text/plain; charset=utf-8", "error adding network"); - } + } } void handleDeleteSavedSSIDs(AsyncWebServerRequest *request) { - const AsyncWebParameter* p = request->getParam("ssid"); + const AsyncWebParameter *p = request->getParam("ssid"); const String ssid = p->value(); bool succ = Wlan_DeleteNetwork(ssid); @@ -1583,8 +1563,8 @@ void handleGetWiFiConfig(AsyncWebServerRequest *request) { request->send(response); } -void handlePostWiFiConfig(AsyncWebServerRequest *request, JsonVariant &json){ - const JsonObject& jsonObj = json.as(); +void handlePostWiFiConfig(AsyncWebServerRequest *request, JsonVariant &json) { + const JsonObject &jsonObj = json.as(); // always perform perform a WiFi scan on startup? bool alwaysScan = jsonObj["scanOnStart"]; @@ -1608,7 +1588,7 @@ void handlePostWiFiConfig(AsyncWebServerRequest *request, JsonVariant &json){ } } -static bool tagIdToJSON(String tagId, JsonObject entry) { +static bool tagIdToJSON(String tagId, JsonObject entry) { String s = gPrefsRfid.getString(tagId.c_str(), "-1"); // Try to lookup rfidId in NVS if (!s.compareTo("-1")) { return false; @@ -1619,7 +1599,7 @@ static bool tagIdToJSON(String tagId, JsonObject entry) { uint32_t _mode = 1; char *token; uint8_t i = 1; - token = strtok((char *)s.c_str(), stringDelimiter); + token = strtok((char *) s.c_str(), stringDelimiter); while (token != NULL) { // Try to extract data from string after lookup if (i == 1) { strncpy(_file, token, sizeof(_file) / sizeof(_file[0])); @@ -1633,12 +1613,12 @@ static bool tagIdToJSON(String tagId, JsonObject entry) { i++; token = strtok(NULL, stringDelimiter); } - entry["id"] = tagId; + entry["id"] = tagId; if (_mode >= 100) { - entry["modId"] = _mode; + entry["modId"] = _mode; } else { entry["fileOrUrl"] = _file; - entry["playMode"] = _mode; + entry["playMode"] = _mode; entry["lastPlayPos"] = _lastPlayPos; entry["trackLastPlayed"] = _trackLastPlayed; } @@ -1646,8 +1626,8 @@ static bool tagIdToJSON(String tagId, JsonObject entry) { } // callback for writing a NVS entry to JSON -bool DumpNvsToJSONCallback(const char * key, void* data) { - JsonArray *myArr = (JsonArray*) data; +bool DumpNvsToJSONCallback(const char *key, void *data) { + JsonArray *myArr = (JsonArray *) data; JsonObject obj = myArr->createNestedObject(); return tagIdToJSON(key, obj); } @@ -1683,7 +1663,7 @@ static void handleGetRFIDRequest(AsyncWebServerRequest *request) { } static void handlePostRFIDRequest(AsyncWebServerRequest *request, JsonVariant &json) { - const JsonObject& jsonObj = json.as(); + const JsonObject &jsonObj = json.as(); String tagId = jsonObj["id"]; if (tagId.isEmpty()) { @@ -1696,13 +1676,13 @@ static void handlePostRFIDRequest(AsyncWebServerRequest *request, JsonVariant &j fileOrUrl = "0"; } char _fileOrUrlAscii[MAX_FILEPATH_LENTGH]; - convertFilenameToAscii(fileOrUrl, _fileOrUrlAscii); + convertFilenameToAscii(fileOrUrl, _fileOrUrlAscii); uint8_t _playModeOrModId; if (jsonObj.containsKey("modId")) { _playModeOrModId = jsonObj["modId"]; } else { _playModeOrModId = jsonObj["playMode"]; - } + } if (_playModeOrModId <= 0) { Log_Println("/rfid (POST): Invalid playMode or modId", LOGLEVEL_ERROR); request->send(500, "text/plain; charset=utf-8", "/rfid (POST): Invalid playMode or modId"); @@ -1752,8 +1732,6 @@ static void handleDeleteRFIDRequest(AsyncWebServerRequest *request) { } } - - // Takes stream from file-upload and writes payload into a temporary sd-file. void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { static File tmpFile; @@ -1773,7 +1751,7 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, } size_t wrote = tmpFile.write(data, len); - if(wrote != len) { + if (wrote != len) { // we did not write all bytes --> fail Log_Printf(LOGLEVEL_ERROR, "Error writing %s. Expected %u, wrote %u (error: %u)!", tmpFile.path(), len, wrote, tmpFile.getWriteError()); return; @@ -1904,22 +1882,21 @@ static void handleCoverImageRequest(AsyncWebServerRequest *request) { } int imageSize = gPlayProperties.coverFileSize; - AsyncWebServerResponse *response = request->beginChunkedResponse(mimeType, [coverFile,imageSize](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - + AsyncWebServerResponse *response = request->beginChunkedResponse(mimeType, [coverFile, imageSize](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { if (maxLen > 1024) { maxLen = 1024; } File file = coverFile; // local copy of file pointer size_t leftToWrite = imageSize - index; - if (! leftToWrite) { - return 0; //end of transfer + if (!leftToWrite) { + return 0; // end of transfer } - size_t willWrite = (leftToWrite > maxLen)?maxLen:leftToWrite; + size_t willWrite = (leftToWrite > maxLen) ? maxLen : leftToWrite; file.read(buffer, willWrite); index += willWrite; return willWrite; }); response->addHeader("Cache Control", "no-cache, must-revalidate"); request->send(response); -} \ No newline at end of file +} diff --git a/src/Wlan.cpp b/src/Wlan.cpp index 52ddcc09..53919cfa 100644 --- a/src/Wlan.cpp +++ b/src/Wlan.cpp @@ -1,34 +1,37 @@ #include -#include -#include -#include #include "settings.h" + +#include "Wlan.h" + #include "AudioPlayer.h" -#include "RotaryEncoder.h" #include "Log.h" +#include "MemX.h" +#include "RotaryEncoder.h" #include "System.h" #include "Web.h" -#include "MemX.h" -#include "main.h" -#include "Wlan.h" #include "esp_sntp.h" +#include "main.h" + +#include +#include +#include -#define WIFI_STATE_INIT 0u +#define WIFI_STATE_INIT 0u #define WIFI_STATE_CONNECT_LAST 1u #define WIFI_STATE_SCAN_CONN 2u #define WIFI_STATE_CONN_SUCCESS 3u #define WIFI_STATE_CONNECTED 4u -#define WIFI_STATE_DISCONNECTED 5u +#define WIFI_STATE_DISCONNECTED 5u #define WIFI_STATE_CONN_FAILED 6u -#define WIFI_STATE_AP 7u -#define WIFI_STATE_END 8u +#define WIFI_STATE_AP 7u +#define WIFI_STATE_END 8u uint8_t wifiState = WIFI_STATE_INIT; #define RECONNECT_INTERVAL 600000 // AP-WiFi -IPAddress apIP(192, 168, 4, 1); // Access-point's static IP +IPAddress apIP(192, 168, 4, 1); // Access-point's static IP IPAddress apNetmask(255, 255, 255, 0); // Access-point's netmask bool wifiEnabled; // Current status if wifi is enabled @@ -46,7 +49,7 @@ static unsigned long connectStartTimestamp = 0; static uint32_t connectionFailedTimestamp = 0; // state for persistent settings -static const char* nvsWiFiNetworksKey = "SAVED_WIFIS"; +static const char *nvsWiFiNetworksKey = "SAVED_WIFIS"; static constexpr size_t maxSavedNetworks = 10; static size_t numKnownNetworks = 0; static WiFiSettings knownNetworks[maxSavedNetworks]; @@ -68,14 +71,13 @@ void Wlan_Init(void) { } // load array of up to maxSavedNetworks from NVS - numKnownNetworks = gPrefsSettings.getBytes(nvsWiFiNetworksKey, knownNetworks, maxSavedNetworks*sizeof(WiFiSettings)) / sizeof(WiFiSettings); + numKnownNetworks = gPrefsSettings.getBytes(nvsWiFiNetworksKey, knownNetworks, maxSavedNetworks * sizeof(WiFiSettings)) / sizeof(WiFiSettings); for (int i = 0; i < numKnownNetworks; i++) { knownNetworks[i].ssid[32] = '\0'; knownNetworks[i].password[64] = '\0'; Log_Printf(LOGLEVEL_NOTICE, wifiNetworkLoaded, i, knownNetworks[i].ssid); } - // ******************* MIGRATION ******************* // migration from single-wifi setup. Delete some time in the future if (gPrefsSettings.isKey("SSID") && gPrefsSettings.isKey("Password")) { @@ -85,31 +87,30 @@ void Wlan_Init(void) { gPrefsSettings.putString("LAST_SSID", strSSID); struct WiFiSettings networkSettings; - + strncpy(networkSettings.ssid, strSSID.c_str(), 32); networkSettings.ssid[32] = '\0'; strncpy(networkSettings.password, strPassword.c_str(), 64); networkSettings.password[64] = '\0'; networkSettings.use_static_ip = false; - #ifdef STATIC_IP_ENABLE - networkSettings.static_addr = (uint32_t) IPAddress(LOCAL_IP); - networkSettings.static_gateway = (uint32_t) IPAddress(GATEWAY_IP); - networkSettings.static_subnet = (uint32_t) IPAddress(SUBNET_IP); - networkSettings.static_dns1 = (uint32_t) IPAddress(DNS_IP); - networkSettings.use_static_ip = true; - #endif +#ifdef STATIC_IP_ENABLE + networkSettings.static_addr = (uint32_t) IPAddress(LOCAL_IP); + networkSettings.static_gateway = (uint32_t) IPAddress(GATEWAY_IP); + networkSettings.static_subnet = (uint32_t) IPAddress(SUBNET_IP); + networkSettings.static_dns1 = (uint32_t) IPAddress(DNS_IP); + networkSettings.use_static_ip = true; +#endif Wlan_AddNetworkSettings(networkSettings); // clean up old values from nvs gPrefsSettings.remove("SSID"); gPrefsSettings.remove("Password"); } - - // ******************* MIGRATION ******************* + // ******************* MIGRATION ******************* - if (OPMODE_NORMAL != System_GetOperationMode()) { + if (OPMODE_NORMAL != System_GetOperationMode()) { wifiState = WIFI_STATE_END; return; } @@ -120,7 +121,7 @@ void Wlan_Init(void) { // Arduino 2.0.x only, comment to use dynamic buffers. // for Arduino 2.0.9 this does not seem to bring any advantage just more memory use, so leave it outcommented - //WiFi.useStaticBuffers(true); + // WiFi.useStaticBuffers(true); wifiState = WIFI_STATE_INIT; handleWifiStateInit(); @@ -135,10 +136,10 @@ void connectToKnownNetwork(WiFiSettings settings, byte *bssid = nullptr) { if (settings.use_static_ip) { Log_Println(tryStaticIpConfig, LOGLEVEL_NOTICE); if (!WiFi.config( - IPAddress(settings.static_addr), - IPAddress(settings.static_gateway), - IPAddress(settings.static_subnet), - IPAddress(settings.static_dns1), + IPAddress(settings.static_addr), + IPAddress(settings.static_gateway), + IPAddress(settings.static_subnet), + IPAddress(settings.static_dns1), IPAddress(settings.static_dns2))) { Log_Println(staticIPConfigFailed, LOGLEVEL_ERROR); } @@ -164,7 +165,7 @@ void handleWifiStateInit() { bool scanWiFiOnStart = gPrefsSettings.getBool("ScanWiFiOnStart", false); if (scanWiFiOnStart) { // perform a scan to find the strongest network with same ssid (e.g. for mesh/repeater networks) - WiFi.scanNetworks(true, false, true, 120); + WiFi.scanNetworks(true, false, true, 120); wifiState = WIFI_STATE_SCAN_CONN; } else { // quick connect without additional scan @@ -184,14 +185,14 @@ void handleWifiStateConnectLast() { WiFi.disconnect(true, true); WiFi.mode(WIFI_STA); - + // for speed, try to connect to last ssid first String lastSSID = gPrefsSettings.getString("LAST_SSID"); std::optional lastSettings = std::nullopt; if (lastSSID) { - for(int i=0; i 1) { + if (!lastSettings || connectionAttemptCounter > 1) { // you can tweak passive/active mode and time per channel // routers send a beacon msg every 100ms and passive mode with 120ms works well and is fastest here WiFi.scanNetworks(true, false, true, 120); @@ -209,7 +210,7 @@ void handleWifiStateConnectLast() { wifiState = WIFI_STATE_SCAN_CONN; return; } - + connectStartTimestamp = millis(); connectToKnownNetwork(lastSettings.value()); connectionAttemptCounter++; @@ -243,7 +244,7 @@ void handleWifiStateScanConnect() { for (int i = 0; i < wifiScanCompleteResult; ++i) { Log_Printf(LOGLEVEL_NOTICE, wifiScanResult, WiFi.SSID(i).c_str(), WiFi.RSSI(i), WiFi.channel(i), WiFi.BSSIDstr(i).c_str()); } - } else { + } else { if (millis() - connectStartTimestamp < 5000) { return; } @@ -258,14 +259,14 @@ void handleWifiStateScanConnect() { byte *bssid = WiFi.BSSID(i); // check if ssid name matches any saved ssid for (int j = 0; j < numKnownNetworks; j++) { - if (strncmp(issid.c_str(), knownNetworks[j].ssid, 32) ==0 ) { + if (strncmp(issid.c_str(), knownNetworks[j].ssid, 32) == 0) { connectToKnownNetwork(knownNetworks[j], bssid); connectStartTimestamp = millis(); // prepare for next iteration if (connectionAttemptCounter > 0) { - scanIndex = i+1; + scanIndex = i + 1; connectionAttemptCounter = 0; } else { scanIndex = i; @@ -282,15 +283,14 @@ void handleWifiStateScanConnect() { } // Callback function (get's called when time adjusts via NTP) -void ntpTimeAvailable(struct timeval *t) -{ +void ntpTimeAvailable(struct timeval *t) { struct tm timeinfo; - if(!getLocalTime(&timeinfo)) { + if (!getLocalTime(&timeinfo)) { Log_Println(ntpFailed, LOGLEVEL_NOTICE); return; } static char timeStringBuff[255]; - snprintf(timeStringBuff, sizeof(timeStringBuff), ntpGotTime, timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); + snprintf(timeStringBuff, sizeof(timeStringBuff), ntpGotTime, timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); Log_Println(timeStringBuff, LOGLEVEL_NOTICE); // set ESPuino's very first start date if (!gPrefsSettings.isKey("firstStart")) { @@ -321,24 +321,24 @@ void handleWifiStateConnectionSuccess() { sntp_set_time_sync_notification_cb(ntpTimeAvailable); // start NTP request with timezone configTzTime(timeZone, "de.pool.ntp.org", "0.pool.ntp.org", "ptbtime1.ptb.de"); - #ifdef MDNS_ENABLE - // zero conf, make device available as .local - if (MDNS.begin(hostname.c_str())) { - MDNS.addService("http", "tcp", 80); - Log_Printf(LOGLEVEL_NOTICE, mDNSStarted, hostname.c_str()); - } else { - Log_Printf(LOGLEVEL_ERROR, mDNSFailed, hostname.c_str()); - } - #endif +#ifdef MDNS_ENABLE + // zero conf, make device available as .local + if (MDNS.begin(hostname.c_str())) { + MDNS.addService("http", "tcp", 80); + Log_Printf(LOGLEVEL_NOTICE, mDNSStarted, hostname.c_str()); + } else { + Log_Printf(LOGLEVEL_ERROR, mDNSFailed, hostname.c_str()); + } +#endif delete dnsServer; dnsServer = nullptr; - - #ifdef PLAY_LAST_RFID_AFTER_REBOOT - if (gPlayLastRfIdWhenWiFiConnected && gTriedToConnectToHost ) { - gPlayLastRfIdWhenWiFiConnected=false; - recoverLastRfidPlayedFromNvs(true); - } - #endif + +#ifdef PLAY_LAST_RFID_AFTER_REBOOT + if (gPlayLastRfIdWhenWiFiConnected && gTriedToConnectToHost) { + gPlayLastRfIdWhenWiFiConnected = false; + recoverLastRfidPlayedFromNvs(true); + } +#endif wifiState = WIFI_STATE_CONNECTED; } @@ -443,7 +443,6 @@ void Wlan_Cyclic(void) { } } - bool Wlan_ValidateHostname(String newHostname) { size_t len = newHostname.length(); const char *hostname = newHostname.c_str(); @@ -451,16 +450,16 @@ bool Wlan_ValidateHostname(String newHostname) { // validation: first char alphanumerical, then alphanumerical or '-', last char alphanumerical // These rules are mainly for mDNS purposes, a "pretty" hostname could have far fewer restrictions bool validated = true; - if(len < 2 || len > 32) { + if (len < 2 || len > 32) { validated = false; } - if(!isAlphaNumeric(hostname[0]) || !isAlphaNumeric(hostname[len-1])) { + if (!isAlphaNumeric(hostname[0]) || !isAlphaNumeric(hostname[len - 1])) { validated = false; } - for(int i = 0; i < len; i++) { - if(!isAlphaNumeric(hostname[i]) && hostname[i] != '-') { + for (int i = 0; i < len; i++) { + if (!isAlphaNumeric(hostname[i]) && hostname[i] != '-') { validated = false; break; } @@ -480,7 +479,7 @@ bool Wlan_AddNetworkSettings(WiFiSettings settings) { settings.ssid[32] = '\0'; settings.password[64] = '\0'; - for (uint8_t i=0; i max_len) { return 0; } - for (uint8_t i=0; isetErrorReplyCode(DNSReplyCode::NoError); dnsServer->start(DNS_PORT, "*", ip); @@ -607,7 +606,7 @@ void writeWifiStatusToNVS(bool wifiStatus) { gPrefsSettings.putUInt("enableWifi", wifiEnabled ? 1 : 0); - if(wifiEnabled) { + if (wifiEnabled) { Log_Println(wifiEnabledMsg, LOGLEVEL_NOTICE); } else { Log_Println(wifiDisabledMsg, LOGLEVEL_NOTICE); diff --git a/src/Wlan.h b/src/Wlan.h index 3f6fb287..ac148107 100644 --- a/src/Wlan.h +++ b/src/Wlan.h @@ -16,7 +16,7 @@ void Wlan_Init(void); void Wlan_Cyclic(void); bool Wlan_AddNetworkSettings(WiFiSettings); uint8_t Wlan_NumSavedNetworks(); -size_t Wlan_GetSSIDs(String*, size_t); +size_t Wlan_GetSSIDs(String *, size_t); const String Wlan_GetCurrentSSID(); const String Wlan_GetHostname(); bool Wlan_DeleteNetwork(String); @@ -27,5 +27,3 @@ void Wlan_ToggleEnable(void); String Wlan_GetIpAddress(void); int8_t Wlan_GetRssi(void); bool Wlan_ConnectionTryInProgress(void); - - diff --git a/src/main.cpp b/src/main.cpp index 93e9f93a..6c2cb2a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,9 @@ // !!! MAKE SURE TO EDIT settings.h !!! #include -#include #include "settings.h" // Contains all user-relevant settings (general) +#include "main.h" + #include "AudioPlayer.h" #include "Battery.h" #include "Bluetooth.h" @@ -10,12 +11,14 @@ #include "Cmd.h" #include "Common.h" #include "Ftp.h" +#include "HallEffectSensor.h" #include "IrReceiver.h" #include "Led.h" #include "Log.h" -#include "Mqtt.h" #include "MemX.h" +#include "Mqtt.h" #include "Port.h" +#include "Power.h" #include "Queues.h" #include "Rfid.h" #include "RotaryEncoder.h" @@ -24,9 +27,8 @@ #include "Web.h" #include "Wlan.h" #include "revision.h" -#include "Power.h" -#include "HallEffectSensor.h" -#include "main.h" + +#include bool gPlayLastRfIdWhenWiFiConnected = false; bool gTriedToConnectToHost = false; @@ -48,101 +50,100 @@ bool testSPIRAM(void) { } #ifdef PLAY_LAST_RFID_AFTER_REBOOT - bool recoverLastRfid = true; - bool recoverBootCount = true; - bool resetBootCount = false; - uint32_t bootCount = 0; +bool recoverLastRfid = true; +bool recoverBootCount = true; +bool resetBootCount = false; +uint32_t bootCount = 0; #endif //////////// #if (HAL == 2) #include "AC101.h" - static TwoWire i2cBusOne = TwoWire(0); - static AC101 ac(&i2cBusOne); +static TwoWire i2cBusOne = TwoWire(0); +static AC101 ac(&i2cBusOne); #endif // I2C #ifdef I2C_2_ENABLE - TwoWire i2cBusTwo = TwoWire(1); +TwoWire i2cBusTwo = TwoWire(1); #endif #ifdef PLAY_LAST_RFID_AFTER_REBOOT - // If a problem occurs, remembering last rfid can lead into a boot loop that's hard to escape of. - // That reason for a mechanism is necessary to prevent this. - // At start of a boot, bootCount is incremented by one and after 30s decremented because - // uptime of 30s is considered as "successful boot". - void recoverBootCountFromNvs(void) { - if (recoverBootCount) { - recoverBootCount = false; - resetBootCount = true; - bootCount = gPrefsSettings.getUInt("bootCount", 999); - - if (bootCount == 999) { // first init - bootCount = 1; - gPrefsSettings.putUInt("bootCount", bootCount); - } else if (bootCount >= 3) { // considered being a bootloop => don't recover last rfid! - bootCount = 1; - gPrefsSettings.putUInt("bootCount", bootCount); - gPrefsSettings.putString("lastRfid", "-1"); // reset last rfid - Log_Println(bootLoopDetected, LOGLEVEL_ERROR); - recoverLastRfid = false; - } else { // normal operation - gPrefsSettings.putUInt("bootCount", ++bootCount); - } - } - - if (resetBootCount && millis() >= 30000) { // reset bootcount - resetBootCount = false; - bootCount = 0; +// If a problem occurs, remembering last rfid can lead into a boot loop that's hard to escape of. +// That reason for a mechanism is necessary to prevent this. +// At start of a boot, bootCount is incremented by one and after 30s decremented because +// uptime of 30s is considered as "successful boot". +void recoverBootCountFromNvs(void) { + if (recoverBootCount) { + recoverBootCount = false; + resetBootCount = true; + bootCount = gPrefsSettings.getUInt("bootCount", 999); + + if (bootCount == 999) { // first init + bootCount = 1; gPrefsSettings.putUInt("bootCount", bootCount); - Log_Println(noBootLoopDetected, LOGLEVEL_INFO); + } else if (bootCount >= 3) { // considered being a bootloop => don't recover last rfid! + bootCount = 1; + gPrefsSettings.putUInt("bootCount", bootCount); + gPrefsSettings.putString("lastRfid", "-1"); // reset last rfid + Log_Println(bootLoopDetected, LOGLEVEL_ERROR); + recoverLastRfid = false; + } else { // normal operation + gPrefsSettings.putUInt("bootCount", ++bootCount); } } - // Get last RFID-tag applied from NVS - void recoverLastRfidPlayedFromNvs(bool force) { - if (recoverLastRfid || force) { - if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { // Don't recover if BT-mode is desired - recoverLastRfid = false; - return; - } + if (resetBootCount && millis() >= 30000) { // reset bootcount + resetBootCount = false; + bootCount = 0; + gPrefsSettings.putUInt("bootCount", bootCount); + Log_Println(noBootLoopDetected, LOGLEVEL_INFO); + } +} + +// Get last RFID-tag applied from NVS +void recoverLastRfidPlayedFromNvs(bool force) { + if (recoverLastRfid || force) { + if (System_GetOperationMode() == OPMODE_BLUETOOTH_SINK) { // Don't recover if BT-mode is desired recoverLastRfid = false; - String lastRfidPlayed = gPrefsSettings.getString("lastRfid", "-1"); - if (!lastRfidPlayed.compareTo("-1")) { - Log_Println(unableToRestoreLastRfidFromNVS, LOGLEVEL_INFO); - } else { - xQueueSend(gRfidCardQueue, lastRfidPlayed.c_str(), 0); - gPlayLastRfIdWhenWiFiConnected = !force; - Log_Printf(LOGLEVEL_INFO, restoredLastRfidFromNVS, lastRfidPlayed.c_str()); - } + return; + } + recoverLastRfid = false; + String lastRfidPlayed = gPrefsSettings.getString("lastRfid", "-1"); + if (!lastRfidPlayed.compareTo("-1")) { + Log_Println(unableToRestoreLastRfidFromNVS, LOGLEVEL_INFO); + } else { + xQueueSend(gRfidCardQueue, lastRfidPlayed.c_str(), 0); + gPlayLastRfIdWhenWiFiConnected = !force; + Log_Printf(LOGLEVEL_INFO, restoredLastRfidFromNVS, lastRfidPlayed.c_str()); } } +} #endif - void setup() { Log_Init(); Queues_Init(); // Make sure all wakeups can be enabled *before* initializing RFID, which can enter sleep immediately - Button_Init(); // To preseed internal button-storage with values - #ifdef PN5180_ENABLE_LPCD - Rfid_Init(); - #endif + Button_Init(); // To preseed internal button-storage with values +#ifdef PN5180_ENABLE_LPCD + Rfid_Init(); +#endif System_Init(); - // Init 2nd i2c-bus if RC522 is used with i2c or if port-expander is enabled - #ifdef I2C_2_ENABLE - i2cBusTwo.begin(ext_IIC_DATA, ext_IIC_CLK); - delay(50); - Log_Println(rfidScannerReady, LOGLEVEL_DEBUG); - #endif +// Init 2nd i2c-bus if RC522 is used with i2c or if port-expander is enabled +#ifdef I2C_2_ENABLE + i2cBusTwo.begin(ext_IIC_DATA, ext_IIC_CLK); + delay(50); + Log_Println(rfidScannerReady, LOGLEVEL_DEBUG); +#endif - #ifdef HALLEFFECT_SENSOR_ENABLE - gHallEffectSensor.init(); - #endif +#ifdef HALLEFFECT_SENSOR_ENABLE + gHallEffectSensor.init(); +#endif // Needs i2c first if port-expander is used Port_Init(); @@ -163,20 +164,20 @@ void setup() { Led_Init(); - // Only used for ESP32-A1S-Audiokit - #if (HAL == 2) - i2cBusOne.begin(IIC_DATA, IIC_CLK, 40000); +// Only used for ESP32-A1S-Audiokit +#if (HAL == 2) + i2cBusOne.begin(IIC_DATA, IIC_CLK, 40000); - while (not ac.begin()) { - Log_Println("AC101 Failed!", LOGLEVEL_ERROR); - delay(1000); - } - Log_Println("AC101 via I2C - OK!", LOGLEVEL_NOTICE); + while (not ac.begin()) { + Log_Println("AC101 Failed!", LOGLEVEL_ERROR); + delay(1000); + } + Log_Println("AC101 via I2C - OK!", LOGLEVEL_NOTICE); - pinMode(22, OUTPUT); - digitalWrite(22, HIGH); - ac.SetVolumeHeadphone(80); - #endif + pinMode(22, OUTPUT); + digitalWrite(22, HIGH); + ac.SetVolumeHeadphone(80); +#endif // Needs power first SdCard_Init(); @@ -197,11 +198,11 @@ void setup() { Ftp_Init(); Mqtt_Init(); - #ifndef PN5180_ENABLE_LPCD - #if defined (RFID_READER_TYPE_MFRC522_SPI) || defined (RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_PN5180) - Rfid_Init(); - #endif +#ifndef PN5180_ENABLE_LPCD + #if defined(RFID_READER_TYPE_MFRC522_SPI) || defined(RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_PN5180) + Rfid_Init(); #endif +#endif RotaryEncoder_Init(); Wlan_Init(); Bluetooth_Init(); @@ -221,9 +222,9 @@ void setup() { Log_Printf(LOGLEVEL_DEBUG, "RSSI: %d dBm", Wlan_GetRssi()); } - #ifdef CONTROLS_LOCKED_BY_DEFAULT - System_SetLockControls(true); - #endif +#ifdef CONTROLS_LOCKED_BY_DEFAULT + System_SetLockControls(true); +#endif } void loop() { @@ -245,20 +246,20 @@ void loop() { AudioPlayer_Cyclic(); Battery_Cyclic(); - //Port_Cyclic(); // called by button (controlled via hw-timer) + // Port_Cyclic(); // called by button (controlled via hw-timer) Button_Cyclic(); System_Cyclic(); Rfid_PreferenceLookupHandler(); - #ifdef PLAY_LAST_RFID_AFTER_REBOOT - recoverBootCountFromNvs(); - recoverLastRfidPlayedFromNvs(); - #endif +#ifdef PLAY_LAST_RFID_AFTER_REBOOT + recoverBootCountFromNvs(); + recoverLastRfidPlayedFromNvs(); +#endif IrReceiver_Cyclic(); vTaskDelay(portTICK_PERIOD_MS * 5u); - #ifdef HALLEFFECT_SENSOR_ENABLE - gHallEffectSensor.cyclic(); - #endif +#ifdef HALLEFFECT_SENSOR_ENABLE + gHallEffectSensor.cyclic(); +#endif } diff --git a/src/main.h b/src/main.h index 3126330e..08092fb1 100644 --- a/src/main.h +++ b/src/main.h @@ -4,6 +4,5 @@ extern bool gPlayLastRfIdWhenWiFiConnected; extern bool gTriedToConnectToHost; #ifdef PLAY_LAST_RFID_AFTER_REBOOT - extern void recoverLastRfidPlayedFromNvs(bool force = false); +extern void recoverLastRfidPlayedFromNvs(bool force = false); #endif - diff --git a/src/settings-azdelivery_sdmmc.h b/src/settings-azdelivery_sdmmc.h index 1cd08ff1..181678c2 100644 --- a/src/settings-azdelivery_sdmmc.h +++ b/src/settings-azdelivery_sdmmc.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_CUSTOM_H__ #define __ESPUINO_SETTINGS_CUSTOM_H__ #include "Arduino.h" diff --git a/src/settings-complete.h b/src/settings-complete.h index 4d0e299e..9a43db4f 100644 --- a/src/settings-complete.h +++ b/src/settings-complete.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_COMPLETE #define __ESPUINO_COMPLETE #include "Arduino.h" diff --git a/src/settings-custom.h b/src/settings-custom.h index 657e18e1..37b91ba7 100644 --- a/src/settings-custom.h +++ b/src/settings-custom.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_CUSTOM_H__ #define __ESPUINO_SETTINGS_CUSTOM_H__ #include "Arduino.h" diff --git a/src/settings-espa1s.h b/src/settings-espa1s.h index 55a23759..6e3f0edc 100644 --- a/src/settings-espa1s.h +++ b/src/settings-espa1s.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_ESPA1S_H__ #define __ESPUINO_SETTINGS_ESPA1S_H__ #include "Arduino.h" diff --git a/src/settings-lolin32.h b/src/settings-lolin32.h index f3c243ab..a0bb668f 100644 --- a/src/settings-lolin32.h +++ b/src/settings-lolin32.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_LOLIN32_H__ #define __ESPUINO_SETTINGS_LOLIN32_H__ #include "Arduino.h" diff --git a/src/settings-lolin_d32.h b/src/settings-lolin_d32.h index 4dcd6245..e108ba14 100644 --- a/src/settings-lolin_d32.h +++ b/src/settings-lolin_d32.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_LOLIN_D32_H__ #define __ESPUINO_SETTINGS_LOLIN_D32_H__ #include "Arduino.h" diff --git a/src/settings-lolin_d32_pro.h b/src/settings-lolin_d32_pro.h index b2df515e..e9d12f3e 100644 --- a/src/settings-lolin_d32_pro.h +++ b/src/settings-lolin_d32_pro.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_LOLIN_D32_PRO_H__ #define __ESPUINO_SETTINGS_LOLIN_D32_PRO_H__ #include "Arduino.h" diff --git a/src/settings-lolin_d32_pro_sdmmc_pe.h b/src/settings-lolin_d32_pro_sdmmc_pe.h index 9a1721de..ba5cd46f 100644 --- a/src/settings-lolin_d32_pro_sdmmc_pe.h +++ b/src/settings-lolin_d32_pro_sdmmc_pe.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_LOLIN_D32_PRO_H__ #define __ESPUINO_SETTINGS_LOLIN_D32_PRO_H__ #include "Arduino.h" diff --git a/src/settings-lolin_d32_sdmmc_pe.h b/src/settings-lolin_d32_sdmmc_pe.h index ff5b1eb5..5f22e57e 100644 --- a/src/settings-lolin_d32_sdmmc_pe.h +++ b/src/settings-lolin_d32_sdmmc_pe.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_LOLIN_D32_H__ #define __ESPUINO_SETTINGS_LOLIN_D32_H__ #include "Arduino.h" diff --git a/src/settings-override.h.sample b/src/settings-override.h.sample index 9a14d378..8b1d2a8b 100644 --- a/src/settings-override.h.sample +++ b/src/settings-override.h.sample @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_OVERRIDE_H__ #define __ESPUINO_SETTINGS_OVERRIDE_H__ #include "Arduino.h" diff --git a/src/settings-ttgo_t8.h b/src/settings-ttgo_t8.h index c3d7feb3..2b385222 100644 --- a/src/settings-ttgo_t8.h +++ b/src/settings-ttgo_t8.h @@ -1,3 +1,5 @@ +// clang-format off + #include "Arduino.h" //######################### INFOS #################################### diff --git a/src/settings.h b/src/settings.h index 2cdff667..14a1d742 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,3 +1,5 @@ +// clang-format off + #ifndef __ESPUINO_SETTINGS_H__ #define __ESPUINO_SETTINGS_H__ #include "Arduino.h" @@ -47,7 +49,7 @@ //#define PLAY_LAST_RFID_AFTER_REBOOT // When restarting ESPuino, the last RFID that was active before, is recalled and played //#define USE_LAST_VOLUME_AFTER_REBOOT // Remembers the volume used at last shutdown after reboot #define USEROTARY_ENABLE // If rotary-encoder is used (don't forget to review WAKEUP_BUTTON if you disable this feature!) - #define BLUETOOTH_ENABLE // If enabled and bluetooth-mode is active, you can stream to your ESPuino or to a headset via bluetooth (a2dp-sink & a2dp-source). Note: This feature consumes a lot of resources and the available flash/ram might not be sufficient. + #define BLUETOOTH_ENABLE // If enabled and bluetooth-mode is active, you can stream to your ESPuino or to a headset via bluetooth (a2dp-sink & a2dp-source). Note: This feature consumes a lot of resources and the available flash/ram might not be sufficient. //#define IR_CONTROL_ENABLE // Enables remote control (https://forum.espuino.de/t/neues-feature-fernsteuerung-per-infrarot-fernbedienung/265) //#define PAUSE_WHEN_RFID_REMOVED // Playback starts when card is applied and pauses automatically, when card is removed (https://forum.espuino.de/t/neues-feature-pausieren-wenn-rfid-karte-entfernt-wurde/541) //#define PAUSE_ON_MIN_VOLUME // When playback is active and volume is changed to zero, playback is paused automatically. Playback is continued if volume reaches 1. (https://forum.espuino.de/t/neues-feature-pausieren-wenn-rfid-karte-entfernt-wurde/541) @@ -65,7 +67,7 @@ //################## select SD card mode ############################# #define SD_MMC_1BIT_MODE // run SD card in SD-MMC 1Bit mode (using GPIOs 15 + 14 + 2 is mandatory!) //#define SINGLE_SPI_ENABLE // If only one SPI-instance should be used instead of two (not yet working!) - //#define NO_SDCARD // enable to start without any SD card, e.g. for a webplayer only. SD card Settings above will be ignored + //#define NO_SDCARD // enable to start without any SD card, e.g. for a webplayer only. SD card Settings above will be ignored //################## select RFID reader ############################## @@ -167,7 +169,7 @@ // Buttons (better leave unchanged if in doubts :-)) constexpr uint8_t buttonDebounceInterval = 50; // Interval in ms to software-debounce buttons constexpr uint16_t intervalToLongPress = 700; // Interval in ms to distinguish between short and long press of buttons - + // Buttons active state: Default 0 for active LOW, 1 for active HIGH e.g. for TTP223 Capacitive Touch Switch Button (FinnBox) #define BUTTON_0_ACTIVE_STATE 0 #define BUTTON_1_ACTIVE_STATE 0 @@ -175,7 +177,7 @@ #define BUTTON_3_ACTIVE_STATE 0 #define BUTTON_4_ACTIVE_STATE 0 #define BUTTON_5_ACTIVE_STATE 0 - + //#define CONTROLS_LOCKED_BY_DEFAULT // If set the controls are locked at boot #define INCLUDE_ROTARY_IN_CONTROLS_LOCK // If set the rotary encoder is locked if controls are locked @@ -195,7 +197,7 @@ // see list of valid timezones: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv // example for Europe/Berlin: "CET-1CEST,M3.5.0,M10.5.0/3" // example for America/Toronto: "EST5EDT,M3.2.0,M11.1.0" - constexpr const char timeZone[] = "CET-1CEST,M3.5.0,M10.5.0/3"; // Europe/Berlin + constexpr const char timeZone[] = "CET-1CEST,M3.5.0,M10.5.0/3"; // Europe/Berlin // ESPuino will create a WiFi if joing existing WiFi was not possible. Name and password can be configured here. constexpr const char accessPointNetworkSSID[] = "ESPuino"; // Access-point's SSID diff --git a/src/values.h b/src/values.h index 3ebaecda..0ee75ddc 100644 --- a/src/values.h +++ b/src/values.h @@ -1,92 +1,91 @@ #pragma once // Operation Mode -#define OPMODE_NORMAL 0 // Normal mode -#define OPMODE_BLUETOOTH_SINK 1 // Bluetooth sink mode. Player acts as as bluetooth speaker. WiFi is deactivated. Music from SD and webstreams can't be played. -#define OPMODE_BLUETOOTH_SOURCE 2 // Bluetooth sourcemode. Player sennds audio to bluetooth speaker/headset. WiFi is deactivated. Music from SD and webstreams can't be played. +#define OPMODE_NORMAL 0 // Normal mode +#define OPMODE_BLUETOOTH_SINK 1 // Bluetooth sink mode. Player acts as as bluetooth speaker. WiFi is deactivated. Music from SD and webstreams can't be played. +#define OPMODE_BLUETOOTH_SOURCE 2 // Bluetooth sourcemode. Player sennds audio to bluetooth speaker/headset. WiFi is deactivated. Music from SD and webstreams can't be played. // Track-Control -#define NO_ACTION 0 // Dummy to unset track-control-command -#define STOP 1 // Stop play -#define PLAY 2 // Start play (currently not used) -#define PAUSEPLAY 3 // Pause/play -#define NEXTTRACK 4 // Next track of playlist -#define PREVIOUSTRACK 5 // Previous track of playlist -#define FIRSTTRACK 6 // First track of playlist -#define LASTTRACK 7 // Last track of playlist +#define NO_ACTION 0 // Dummy to unset track-control-command +#define STOP 1 // Stop play +#define PLAY 2 // Start play (currently not used) +#define PAUSEPLAY 3 // Pause/play +#define NEXTTRACK 4 // Next track of playlist +#define PREVIOUSTRACK 5 // Previous track of playlist +#define FIRSTTRACK 6 // First track of playlist +#define LASTTRACK 7 // Last track of playlist // Playmodes -#define NO_PLAYLIST 0 // If no playlist is active -#define SINGLE_TRACK 1 // Play a single track -#define SINGLE_TRACK_LOOP 2 // Play a single track in infinite-loop -#define SINGLE_TRACK_OF_DIR_RANDOM 12 // Play a single track of a directory and fall asleep subsequently -#define AUDIOBOOK 3 // Single track, can save last play-position -#define AUDIOBOOK_LOOP 4 // Single track as infinite-loop, can save last play-position -#define ALL_TRACKS_OF_DIR_SORTED 5 // Play all files of a directory (alph. sorted) -#define ALL_TRACKS_OF_DIR_RANDOM 6 // Play all files of a directory (randomized) -#define ALL_TRACKS_OF_DIR_SORTED_LOOP 7 // Play all files of a directory (alph. sorted) in infinite-loop -#define ALL_TRACKS_OF_DIR_RANDOM_LOOP 9 // Play all files of a directory (randomized) in infinite-loop -#define RANDOM_SUBDIRECTORY_OF_DIRECTORY 13 // Picks a random subdirectory from a given directory and do ALL_TRACKS_OF_DIR_SORTED -#define RANDOM_SUBDIRECTORY_OF_DIRECTORY_ALL_TRACKS_OF_DIR_RANDOM 14 // Picks a random subdirectory from a given directory and do ALL_TRACKS_OF_DIR_RANDOM -#define WEBSTREAM 8 // Play webradio-stream -#define LOCAL_M3U 11 // Plays items (webstream or files) with addresses/paths from a local m3u-file -#define BUSY 10 // Used if playlist is created - +#define NO_PLAYLIST 0 // If no playlist is active +#define SINGLE_TRACK 1 // Play a single track +#define SINGLE_TRACK_LOOP 2 // Play a single track in infinite-loop +#define SINGLE_TRACK_OF_DIR_RANDOM 12 // Play a single track of a directory and fall asleep subsequently +#define AUDIOBOOK 3 // Single track, can save last play-position +#define AUDIOBOOK_LOOP 4 // Single track as infinite-loop, can save last play-position +#define ALL_TRACKS_OF_DIR_SORTED 5 // Play all files of a directory (alph. sorted) +#define ALL_TRACKS_OF_DIR_RANDOM 6 // Play all files of a directory (randomized) +#define ALL_TRACKS_OF_DIR_SORTED_LOOP 7 // Play all files of a directory (alph. sorted) in infinite-loop +#define ALL_TRACKS_OF_DIR_RANDOM_LOOP 9 // Play all files of a directory (randomized) in infinite-loop +#define RANDOM_SUBDIRECTORY_OF_DIRECTORY 13 // Picks a random subdirectory from a given directory and do ALL_TRACKS_OF_DIR_SORTED +#define RANDOM_SUBDIRECTORY_OF_DIRECTORY_ALL_TRACKS_OF_DIR_RANDOM 14 // Picks a random subdirectory from a given directory and do ALL_TRACKS_OF_DIR_RANDOM +#define WEBSTREAM 8 // Play webradio-stream +#define LOCAL_M3U 11 // Plays items (webstream or files) with addresses/paths from a local m3u-file +#define BUSY 10 // Used if playlist is created // RFID-modifcation-types -#define CMD_NOTHING 0 // Do Nothing -#define CMD_LOCK_BUTTONS_MOD 100 // Locks all buttons and rotary encoder -#define CMD_SLEEP_TIMER_MOD_15 101 // Puts uC into deepsleep after 15 minutes + LED-DIMM -#define CMD_SLEEP_TIMER_MOD_30 102 // Puts uC into deepsleep after 30 minutes + LED-DIMM -#define CMD_SLEEP_TIMER_MOD_60 103 // Puts uC into deepsleep after 60 minutes + LED-DIMM -#define CMD_SLEEP_TIMER_MOD_120 104 // Puts uC into deepsleep after 120 minutes + LED-DIMM -#define CMD_SLEEP_AFTER_END_OF_TRACK 105 // Puts uC into deepsleep after track is finished + LED-DIMM -#define CMD_SLEEP_AFTER_END_OF_PLAYLIST 106 // Puts uC into deepsleep after playlist is finished + LED-DIMM -#define CMD_SLEEP_AFTER_5_TRACKS 107 // Puts uC into deepsleep after five tracks + LED-DIMM -#define CMD_REPEAT_PLAYLIST 110 // Changes active playmode to endless-loop (for a playlist) -#define CMD_REPEAT_TRACK 111 // Changes active playmode to endless-loop (for a single track) -#define CMD_DIMM_LEDS_NIGHTMODE 120 // Changes LED-brightness -#define CMD_TOGGLE_WIFI_STATUS 130 // Toggles WiFi-status -#define CMD_TOGGLE_BLUETOOTH_SINK_MODE 140 // Toggles Normal/Bluetooth sink Mode -#define CMD_TOGGLE_BLUETOOTH_SOURCE_MODE 141 // Toggles Normal/Bluetooth source Mode -#define CMD_ENABLE_FTP_SERVER 150 // Enables FTP-server -#define CMD_TELL_IP_ADDRESS 151 // Command: ESPuino announces its IP-address via speech -#define CMD_TELL_CURRENT_TIME 152 // Command: ESPuino announces current time via speech +#define CMD_NOTHING 0 // Do Nothing +#define CMD_LOCK_BUTTONS_MOD 100 // Locks all buttons and rotary encoder +#define CMD_SLEEP_TIMER_MOD_15 101 // Puts uC into deepsleep after 15 minutes + LED-DIMM +#define CMD_SLEEP_TIMER_MOD_30 102 // Puts uC into deepsleep after 30 minutes + LED-DIMM +#define CMD_SLEEP_TIMER_MOD_60 103 // Puts uC into deepsleep after 60 minutes + LED-DIMM +#define CMD_SLEEP_TIMER_MOD_120 104 // Puts uC into deepsleep after 120 minutes + LED-DIMM +#define CMD_SLEEP_AFTER_END_OF_TRACK 105 // Puts uC into deepsleep after track is finished + LED-DIMM +#define CMD_SLEEP_AFTER_END_OF_PLAYLIST 106 // Puts uC into deepsleep after playlist is finished + LED-DIMM +#define CMD_SLEEP_AFTER_5_TRACKS 107 // Puts uC into deepsleep after five tracks + LED-DIMM +#define CMD_REPEAT_PLAYLIST 110 // Changes active playmode to endless-loop (for a playlist) +#define CMD_REPEAT_TRACK 111 // Changes active playmode to endless-loop (for a single track) +#define CMD_DIMM_LEDS_NIGHTMODE 120 // Changes LED-brightness +#define CMD_TOGGLE_WIFI_STATUS 130 // Toggles WiFi-status +#define CMD_TOGGLE_BLUETOOTH_SINK_MODE 140 // Toggles Normal/Bluetooth sink Mode +#define CMD_TOGGLE_BLUETOOTH_SOURCE_MODE 141 // Toggles Normal/Bluetooth source Mode +#define CMD_ENABLE_FTP_SERVER 150 // Enables FTP-server +#define CMD_TELL_IP_ADDRESS 151 // Command: ESPuino announces its IP-address via speech +#define CMD_TELL_CURRENT_TIME 152 // Command: ESPuino announces current time via speech -#define CMD_PLAYPAUSE 170 // Command: play/pause -#define CMD_PREVTRACK 171 // Command: previous track -#define CMD_NEXTTRACK 172 // Command: next track -#define CMD_FIRSTTRACK 173 // Command: first track -#define CMD_LASTTRACK 174 // Command: last track -#define CMD_VOLUMEINIT 175 // Command: set volume to initial value -#define CMD_VOLUMEUP 176 // Command: increase volume by 1 -#define CMD_VOLUMEDOWN 177 // Command: lower volume by 1 -#define CMD_MEASUREBATTERY 178 // Command: Measure battery-voltage -#define CMD_SLEEPMODE 179 // Command: Go to deepsleep -#define CMD_SEEK_FORWARDS 180 // Command: jump forwards (time period to jump (in seconds) is configured via settings.h: jumpOffset) -#define CMD_SEEK_BACKWARDS 181 // Command: jump backwards (time period to jump (in seconds) is configured via settings.h: jumpOffset) -#define CMD_STOP 182 // Command: stops playback -#define CMD_RESTARTSYSTEM 183 // Command: restart System +#define CMD_PLAYPAUSE 170 // Command: play/pause +#define CMD_PREVTRACK 171 // Command: previous track +#define CMD_NEXTTRACK 172 // Command: next track +#define CMD_FIRSTTRACK 173 // Command: first track +#define CMD_LASTTRACK 174 // Command: last track +#define CMD_VOLUMEINIT 175 // Command: set volume to initial value +#define CMD_VOLUMEUP 176 // Command: increase volume by 1 +#define CMD_VOLUMEDOWN 177 // Command: lower volume by 1 +#define CMD_MEASUREBATTERY 178 // Command: Measure battery-voltage +#define CMD_SLEEPMODE 179 // Command: Go to deepsleep +#define CMD_SEEK_FORWARDS 180 // Command: jump forwards (time period to jump (in seconds) is configured via settings.h: jumpOffset) +#define CMD_SEEK_BACKWARDS 181 // Command: jump backwards (time period to jump (in seconds) is configured via settings.h: jumpOffset) +#define CMD_STOP 182 // Command: stops playback +#define CMD_RESTARTSYSTEM 183 // Command: restart System // Repeat-Modes -#define NO_REPEAT 0 // No repeat -#define TRACK 1 // Repeat current track (infinite loop) -#define PLAYLIST 2 // Repeat whole playlist (infinite loop) -#define TRACK_N_PLAYLIST 3 // Repeat both (infinite loop) +#define NO_REPEAT 0 // No repeat +#define TRACK 1 // Repeat current track (infinite loop) +#define PLAYLIST 2 // Repeat whole playlist (infinite loop) +#define TRACK_N_PLAYLIST 3 // Repeat both (infinite loop) // Seek-modes -#define SEEK_NORMAL 0 // Normal play -#define SEEK_FORWARDS 1 // Seek forwards -#define SEEK_BACKWARDS 2 // Seek backwards +#define SEEK_NORMAL 0 // Normal play +#define SEEK_FORWARDS 1 // Seek forwards +#define SEEK_BACKWARDS 2 // Seek backwards // TTS -#define TTS_NONE 0 // Do nothng (IDLE) -#define TTS_IP_ADDRESS 1 // Tell IP-address -#define TTS_CURRENT_TIME 2 // Tell current time +#define TTS_NONE 0 // Do nothng (IDLE) +#define TTS_IP_ADDRESS 1 // Tell IP-address +#define TTS_CURRENT_TIME 2 // Tell current time // supported languages -#define DE 1 -#define EN 2 +#define DE 1 +#define EN 2 // Debug -#define PRINT_TASK_STATS 900 // Prints task stats for debugging, needs CONFIG_FREERTOS_USE_TRACE_FACILITY=y and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y in sdkconfig.defaults +#define PRINT_TASK_STATS 900 // Prints task stats for debugging, needs CONFIG_FREERTOS_USE_TRACE_FACILITY=y and CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y in sdkconfig.defaults