Skip to content

Commit

Permalink
changes: * enable access to 3 buttons below display (use M5.Touch as …
Browse files Browse the repository at this point in the history
…M5.BtnA.read() does not work)

           ! option to e.g. use A and B for multipage GUI
         * store index of song played last as json to SPIFFS
           * identify SD and apply last index to correct SD
             ! consider storing config for more than one SD - but how to limit data size?
           * also store last volume
             ! however always use safe low default volume
           ! having a callback/event/interrupt on power press would allow to store config state at power-off only
           ! storing actual playing position is more complex and costly (needs timer e.g. 1s or power-off method)
             * see m5stack/M5Core2#100 ("No detection of power button press · Issue #100 · m5stack/M5Core2 · GitHub")
             * power button press is not suficient, what happens when SD gets removed while playing (temp. store until power button?)
               what happens when bat gets empty? -> timer might be only general solution, may be combined with power button detection
           * see also https://github.com/vshymanskyy/Preferences (by default does not use SPIFFS but flash)
  • Loading branch information
drtrigon committed Dec 7, 2023
1 parent d1b5459 commit dd98f7f
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 21 deletions.
110 changes: 90 additions & 20 deletions src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,8 @@ void CPlayer::begin()
initializeGui();

// initialize Player (should be put into own method)
// hacky as int has size of 4 - should be using struct or json
// also store additional info to identify the SD and check whether its the same as last time
// also consider (re)storing state of volume and playback position within current file
File status = SPIFFS.open("/status", FILE_READ);
if (status) {
m_activeSongIdx = int(status.read()); // hacky as int has size 4, works up to 255 only!

m_audio.connecttoSD(m_songFiles[m_activeSongIdx].c_str());
}
status.close();
Serial.printf("SD Card Size: %lluMB\n", SD.cardSize() / (1024 * 1024)); // FUTURE: use to generate unique SD ID
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024)); // FUTURE: use to generate unique SD ID
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024)); // FUTURE: use to generate unique SD ID
loadConfiguration("");
--m_activeSongIdx; // we start using startNextSong() in loop()
}

void CPlayer::loop()
Expand Down Expand Up @@ -153,10 +142,15 @@ void CPlayer::handleTouchEvents()
{
const auto touchPoint = M5.Touch.getPressPoint();

//Serial.print(M5.BtnA.read());
//Serial.print(M5.BtnB.read());
//Serial.println(M5.BtnC.read());
// not working, see also https://docs.m5stack.com/en/api/core2/button and https://github.com/m5stack/M5Core2/blob/master/examples/Basics/button/button.ino

const bool isButtonPressed = (touchPoint.x > -1 && touchPoint.y > -1);
if (!isButtonPressed)
{
return;
return;
}

if (m_nextSongWidget.isTouched(touchPoint))
Expand Down Expand Up @@ -192,6 +186,22 @@ void CPlayer::handleTouchEvents()
vibrate();
setPosSong(m_progressWidget.getPosition(touchPoint));
}

if (touchPoint.y >= 250) // "capacitive" Buttons A, B, C below display
{
if ((0 <= touchPoint.x) && (touchPoint.x <= 100)) // BtnA
{
Serial.println("M5.BtnA");
}
else if ((105 <= touchPoint.x) && (touchPoint.x <= 205)) // BtnB
{
Serial.println("M5.BtnB");
}
else if ((210 <= touchPoint.x) && (touchPoint.x <= 310)) // BtnC
{
Serial.println("M5.BtnC");
}
}
}

void CPlayer::startNextSong()
Expand All @@ -210,9 +220,7 @@ void CPlayer::startNextSong()

m_audio.connecttoSD(m_songFiles[m_activeSongIdx].c_str());

File status = SPIFFS.open("/status", FILE_WRITE);
status.write(char(m_activeSongIdx)); // hacky as int has size 4, works up to 255 only!
status.close();
saveConfiguration("");
}

void CPlayer::startPrevSong()
Expand All @@ -231,9 +239,7 @@ void CPlayer::startPrevSong()

m_audio.connecttoSD(m_songFiles[m_activeSongIdx].c_str());

File status = SPIFFS.open("/status", FILE_WRITE);
status.write(char(m_activeSongIdx)); // hacky as int has size 4, works up to 255 only!
status.close();
saveConfiguration("");
}

void CPlayer::pauseSong()
Expand Down Expand Up @@ -311,4 +317,68 @@ void CPlayer::vibrate()
M5.Axp.SetLDOEnable(3, false);
}

void CPlayer::loadConfiguration(const char *filename)
{
// Open file for reading
File file = SPIFFS.open("/status", FILE_READ);

// Allocate a temporary JsonDocument
// Don't forget to change the capacity to match your requirements.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<512> doc;

// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, file);
if (error)
Serial.println(F("Failed to read file, using default configuration"));

// Copy values from the JsonDocument to the Config
if ((doc["sd_cardSize"] == SD.cardSize()) &&
(doc["sd_totalBytes"] == SD.totalBytes()) &&
(doc["sd_usedBytes"] == SD.usedBytes()))
{
m_activeSongIdx = doc["m_activeSongIdx"] | m_activeSongIdx;
// we do not restore volume as environmental conditions might have changed
// instead we use always a safe low default to protect user
//m_currentVolume = doc["m_currentVolume"] | m_currentVolume;
}

// Close the file (Curiously, File's destructor doesn't close the file)
file.close();
}

void CPlayer::saveConfiguration(const char *filename)
{
// Delete existing file, otherwise the configuration is appended to the file
SPIFFS.remove("/status");

// Open file for writing
File file = SPIFFS.open("/status", FILE_WRITE);
if (!file) {
Serial.println(F("Failed to create file"));
return;
}

// Allocate a temporary JsonDocument
// Don't forget to change the capacity to match your requirements.
// Use arduinojson.org/assistant to compute the capacity.
StaticJsonDocument<256> doc;

// Set the values in the document
doc["sd_cardSize"] = SD.cardSize();
doc["sd_totalBytes"] = SD.totalBytes();
doc["sd_usedBytes"] = SD.usedBytes();
doc["m_activeSongIdx"] = m_activeSongIdx;
doc["m_currentVolume"] = m_currentVolume;
//doc["..."] = m_audio.getAudioCurrentTime(); // (store current playing position)

// Serialize JSON to file
if (serializeJson(doc, file) == 0) {
Serial.println(F("Failed to write to file"));
}

// Close the file
file.close();
}

} // namespace singsang
6 changes: 5 additions & 1 deletion src/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <SPIFFS.h>
#include <WiFi.h>

#include <ArduinoJson.h>

#include <memory>
#include <vector>

Expand Down Expand Up @@ -56,11 +58,13 @@ class CPlayer
void populateMusicFileList();
void updateGui();
void vibrate();
void loadConfiguration(const char *filename);
void saveConfiguration(const char *filename);

Audio m_audio{};

int m_currentVolume{8};
int m_activeSongIdx{-1};
int m_activeSongIdx{0};
unsigned int m_turnOffAfterInactiveForMilliSec{5 * 60 * 1000};
unsigned int m_lastActivityTimestamp{0};
std::vector<String> m_songFiles{};
Expand Down

0 comments on commit dd98f7f

Please sign in to comment.