diff --git a/README.md b/README.md index 2270b41..6e364a7 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,11 @@ Work is in progress... --- ## Version history +#### v0.9.235 +- SD card playlist moved from SPIFFS to SD card +- new parameter #define SD_MAX_LEVELS - Search depth for files on SD card +- fixed bugs with SD card in multi-threaded mode + #### v0.9.220 - fixed SD prelist indexing error when switching Web>>SD - fixed a bug of switching to the next track when accidentally playing SD diff --git a/yoRadio/locale/displayL10n_en.h b/yoRadio/locale/displayL10n_en.h index 9530245..69d2e54 100644 --- a/yoRadio/locale/displayL10n_en.h +++ b/yoRadio/locale/displayL10n_en.h @@ -65,7 +65,7 @@ const char const_DlgLost[] PROGMEM = "* LOST *"; const char const_DlgUpdate[] PROGMEM = "* UPDATING *"; const char const_DlgNextion[] PROGMEM = "* NEXTION *"; const char const_getWeather[] PROGMEM = ""; -const char const_waitForSD[] PROGMEM = "WAIT FOR SD"; +const char const_waitForSD[] PROGMEM = "INDEX SD"; const char apNameTxt[] PROGMEM = "AP NAME"; const char apPassTxt[] PROGMEM = "PASSWORD"; diff --git a/yoRadio/locale/displayL10n_ru.h b/yoRadio/locale/displayL10n_ru.h index 95900af..d3515c0 100644 --- a/yoRadio/locale/displayL10n_ru.h +++ b/yoRadio/locale/displayL10n_ru.h @@ -65,7 +65,7 @@ const char const_DlgLost[] PROGMEM = "ОТКЛЮЧЕНО"; const char const_DlgUpdate[] PROGMEM = "ОБНОВЛЕНИЕ"; const char const_DlgNextion[] PROGMEM = "NEXTION"; const char const_getWeather[] PROGMEM = ""; -const char const_waitForSD[] PROGMEM = "ОЖИДАНИЕ SD"; +const char const_waitForSD[] PROGMEM = "ИНДЕКС SD"; const char apNameTxt[] PROGMEM = "ТОЧКА ДОСТУПА"; const char apPassTxt[] PROGMEM = "ПАРОЛЬ"; diff --git a/yoRadio/src/core/config.cpp b/yoRadio/src/core/config.cpp index 10633f8..c0ed15f 100644 --- a/yoRadio/src/core/config.cpp +++ b/yoRadio/src/core/config.cpp @@ -63,7 +63,7 @@ void Config::init() { if(emptyFS) BOOTLOG("SPIFFS is empty!"); ssidsCount = 0; _cardStatus = CS_NONE; - mountSDbusy = false; + _SDplaylistFS = getMode()==PM_SDCARD?&SD:(true?&SPIFFS:_SDplaylistFS); if(SDC_CS!=255) randomSeed(analogRead(SDC_CS)); backupSDStation = 0; //checkSD(); @@ -71,8 +71,8 @@ void Config::init() { bootInfo(); } +#ifdef USE_SD bool Config::_sdCardIsConnected() { -#if SDC_CS!=255 sdog.takeMutex(); if(SD.sectorSize()<1) { sdog.giveMutex(); @@ -83,8 +83,6 @@ bool Config::_sdCardIsConnected() { if(SD.sectorSize()>0 && !bread) SD.end(); sdog.giveMutex(); return bread; -#endif - return false; } bool Config::_sdBegin(){ @@ -102,8 +100,6 @@ bool Config::_sdBegin(){ } void Config::checkSD(){ -#if SDC_CS!=255 - mountSDbusy = true; cardStatus_e prevCardStatus = _cardStatus; if(_sdCardIsConnected()){ if(_cardStatus==CS_NONE || _cardStatus==CS_PRESENT || _cardStatus==CS_EJECTED) { @@ -119,22 +115,10 @@ void Config::checkSD(){ } backupSDStation = 0; } - mountSDbusy = false; -#endif -} - -bool Config::spiffsCleanup(){ - bool ret = (SPIFFS.exists(PLAYLIST_SD_PATH)) || (SPIFFS.exists(INDEX_SD_PATH)) || (SPIFFS.exists(INDEX_PATH)); - if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_SD_PATH); - if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); - if(SPIFFS.exists(INDEX_PATH)) SPIFFS.remove(INDEX_PATH); - return ret; } void Config::_mountSD(){ -#if SDC_CS!=255 - if(SDC_CS==255 || mountSDbusy || display.mode()==SDCHANGE) return; - mountSDbusy = true; + if(display.mode()==SDCHANGE) return; sdog.takeMutex(); uint16_t ssz = SD.sectorSize(); sdog.giveMutex(); if(ssz<1) SDinit = _sdBegin(); if(!_sdCardIsConnected()) { @@ -150,14 +134,155 @@ void Config::_mountSD(){ } } } - mountSDbusy = false; -#endif +} + +void Config::changeMode(int newmode){ + if(!SDinit) { + _mountSD(); + if(!SDinit){ + Serial.println("##[ERROR]#\tSD Not Found"); + netserver.requestOnChange(GETPLAYERMODE, 0); + return; + } + } + if(getMode()==PM_SDCARD) store.lastStation = config.backupLastStation; + if(newmode<0){ + store.play_mode++; + if(getMode() > MAX_PLAY_MODE){ + store.play_mode=0; + } + }else{ + store.play_mode=(playMode_e)newmode; + } + save(); + _SDplaylistFS = getMode()==PM_SDCARD?&SD:(true?&SPIFFS:_SDplaylistFS); + if(getMode()==PM_SDCARD && _cardStatus!=CS_MOUNTED){ + display.putRequest(NEWMODE, SDCHANGE); + while(display.mode()!=SDCHANGE) + delay(10); + delay(50); + } + initPlaylistMode(); + if (store.smartstart == 1) player.sendCommand({PR_PLAY, store.lastStation}); + //else + // player.sendCommand({PR_STOP, 0}); + netserver.resetQueue(); + netserver.requestOnChange(GETPLAYERMODE, 0); + netserver.requestOnChange(GETMODE, 0); + display.resetQueue(); + display.putRequest(NEWMODE, PLAYER); + display.putRequest(NEWSTATION); +} + +bool endsWith (const char* base, const char* str) { + int slen = strlen(str) - 1; + const char *p = base + strlen(base) - 1; + while(p > base && isspace(*p)) p--; + p -= slen; + if (p < base) return false; + return (strncmp(p, str, slen) == 0); +} + +uint32_t sdFCount; +void Config::listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels){ + sdog.takeMutex(); File root = SD.open(dirname); sdog.giveMutex(); + if(!root){ + Serial.println("##[ERROR]#\tFailed to open directory"); + return; + } + sdog.takeMutex(); + if(!root.isDirectory()){ + Serial.println("##[ERROR]#\tNot a directory"); + sdog.giveMutex(); + return; + } + sdog.giveMutex(); + sdog.takeMutex(); File file = root.openNextFile(); sdog.giveMutex(); + uint32_t pos = 0; + while(file){ + vTaskDelay(2); + sdog.takeMutex(); + bool fid = file.isDirectory(); + const char * fp = file.path(); + const char * fn = file.name(); + sdog.giveMutex(); + if(fid){ + if(levels && !checkNoMedia(fp)){ + listSD(plSDfile, plSDindex, fp, levels -1); + } + } else { + if(endsWith(strlwr((char*)fn), ".mp3") || endsWith(fn, ".m4a") || endsWith(fn, ".aac") || endsWith(fn, ".wav") || endsWith(fn, ".flac")){ + sdog.takeMutex(); + pos = plSDfile.position(); + plSDfile.print(fn); plSDfile.print("\t"); plSDfile.print(fp); plSDfile.print("\t"); plSDfile.println(0); + plSDindex.write((byte *) &pos, 4); + sdog.giveMutex(); + Serial.print("."); + if(display.mode()==SDCHANGE) display.putRequest(SDFILEINDEX, sdFCount+1); + sdFCount++; + if(sdFCount%64==0) Serial.println(); + } + } + sdog.takeMutex(); if(file) file.close(); file = root.openNextFile(); sdog.giveMutex(); + } + sdog.takeMutex(); if(root) root.close(); sdog.giveMutex(); +} + +void Config::indexSDPlaylist() { + sdFCount = 0; + sdog.takeMutex(); + if(SDPLFS()->exists(PLAYLIST_SD_PATH)) SDPLFS()->remove(PLAYLIST_SD_PATH); + if(SDPLFS()->exists(INDEX_SD_PATH)) SDPLFS()->remove(INDEX_SD_PATH); + File playlist = SDPLFS()->open(PLAYLIST_SD_PATH, "w", true); + sdog.giveMutex(); + if (!playlist) { + return; + } + sdog.takeMutex(); + File index = SDPLFS()->open(INDEX_SD_PATH, "w", true); + sdog.giveMutex(); + listSD(playlist, index, "/", SD_MAX_LEVELS); + sdog.takeMutex(); + index.flush(); + index.close(); + playlist.flush(); + playlist.close(); + sdog.giveMutex(); + Serial.println(); + delay(50); +} + +void Config::initSDPlaylist(bool doIndex) { + store.countStation = 0; + if(doIndex) indexSDPlaylist(); + sdog.takeMutex(); + if (SDPLFS()->exists(INDEX_SD_PATH)) { + File index = SDPLFS()->open(INDEX_SD_PATH, "r"); + store.countStation = index.size() / 4; + if(doIndex){ + store.lastStation = random(1, store.countStation); + backupSDStation = store.lastStation; + } + index.close(); + save(); + } + sdog.giveMutex(); +} + +#endif //#ifdef USE_SD + +bool Config::spiffsCleanup(){ + bool ret = (SPIFFS.exists(PLAYLIST_SD_PATH)) || (SPIFFS.exists(INDEX_SD_PATH)) || (SPIFFS.exists(INDEX_PATH)); + if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_SD_PATH); + if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); + if(SPIFFS.exists(INDEX_PATH)) SPIFFS.remove(INDEX_PATH); + return ret; } void Config::initPlaylistMode(){ sdResumePos = 0; SDinit = false; - if(SDC_CS!=255){ + #ifdef USE_SD if(!_sdBegin()){ store.play_mode=PM_WEB; Serial.println("SD Mount Failed"); @@ -178,14 +303,13 @@ void Config::initPlaylistMode(){ } SDinit = true; } - }else{ - store.play_mode=PM_WEB; - } + #else + store.play_mode=PM_WEB; + #endif if(getMode()==PM_WEB && !emptyFS) initPlaylist(); if (store.lastStation == 0 && store.countStation > 0) { store.lastStation = getMode()==PM_WEB?1:random(1, store.countStation); - //save(); } save(); _bootDone = true; @@ -346,45 +470,6 @@ void Config::setSnuffle(bool sn){ if(sdSnuffle) player.next(); } -void Config::changeMode(int newmode){ -#if SDC_CS!=255 - if(SDC_CS==255) return; - if(!SDinit) { - _mountSD(); - if(!SDinit){ - Serial.println("##[ERROR]#\tSD Not Found"); - netserver.requestOnChange(GETPLAYERMODE, 0); - return; - } - } - if(getMode()==PM_SDCARD) store.lastStation = config.backupLastStation; - if(newmode<0){ - store.play_mode++; - if(getMode() > MAX_PLAY_MODE){ - store.play_mode=0; - } - }else{ - store.play_mode=(playMode_e)newmode; - } - save(); - if(getMode()==PM_SDCARD && _cardStatus!=CS_MOUNTED){ - display.putRequest(NEWMODE, SDCHANGE); - while(display.mode()!=SDCHANGE) - delay(10); - delay(50); - } - initPlaylistMode(); - - if (store.smartstart == 1) player.sendCommand({PR_PLAY, store.lastStation}); - else - player.sendCommand({PR_STOP, 0}); - netserver.requestOnChange(GETPLAYERMODE, 0); - netserver.requestOnChange(GETMODE, 0); - display.putRequest(NEWMODE, PLAYER); - display.putRequest(NEWSTATION); -#endif -} - #if IR_PIN!=255 void Config::saveIR(){ eepromWrite(EEPROM_START_IR, ircodes); @@ -484,15 +569,6 @@ void Config::initPlaylist() { save(); } } - -bool endsWith (const char* base, const char* str) { - int slen = strlen(str) - 1; - const char *p = base + strlen(base) - 1; - while(p > base && isspace(*p)) p--; - p -= slen; - if (p < base) return false; - return (strncmp(p, str, slen) == 0); -} bool Config::checkNoMedia(const char* path){ char nomedia[BUFLEN]= {0}; @@ -502,75 +578,6 @@ bool Config::checkNoMedia(const char* path){ return nm; } -void Config::listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels){ - sdog.takeMutex(); File root = SD.open(dirname); sdog.giveMutex(); - if(!root){ - Serial.println("##[ERROR]#\tFailed to open directory"); - return; - } - if(!root.isDirectory()){ - Serial.println("##[ERROR]#\tNot a directory"); - return; - } - - sdog.takeMutex(); File file = root.openNextFile(); sdog.giveMutex(); - uint32_t pos = 0; - //vTaskDelay(5); - while(file){ - sdog.takeMutex(); - bool fid = file.isDirectory(); - const char * fp = file.path(); - const char * fn = file.name(); - sdog.giveMutex(); - if(fid){ - if(levels && !checkNoMedia(fp)){ - listSD(plSDfile, plSDindex, fp, levels -1); - } - } else { - if(endsWith(strlwr((char*)fn), ".mp3") || endsWith(fn, ".m4a") || endsWith(fn, ".aac") || endsWith(fn, ".wav") || endsWith(fn, ".flac")){ - pos = plSDfile.position(); - plSDfile.print(fn); plSDfile.print("\t"); plSDfile.print(fp); plSDfile.print("\t"); plSDfile.println(0); - plSDindex.write((byte *) &pos, 4); - } - } - sdog.takeMutex(); file = root.openNextFile(); sdog.giveMutex(); - } -} - -void Config::indexSDPlaylist() { - mountSDbusy = true; - if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_SD_PATH); - if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); - File playlist = SPIFFS.open(PLAYLIST_SD_PATH, "w"); - if (!playlist) { - mountSDbusy = false; - return; - } - File index = SPIFFS.open(INDEX_SD_PATH, "w"); - listSD(playlist, index, "/", 2); - index.flush(); - index.close(); - playlist.flush(); - playlist.close(); - delay(50); - mountSDbusy = false; -} - -void Config::initSDPlaylist(bool doIndex) { - store.countStation = 0; - if(doIndex) indexSDPlaylist(); - if (SPIFFS.exists(INDEX_SD_PATH)) { - File index = SPIFFS.open(INDEX_SD_PATH, "r"); - store.countStation = index.size() / 4; - if(doIndex){ - store.lastStation = random(1, store.countStation); - backupSDStation = store.lastStation; - } - index.close(); - save(); - } -} - void Config::loadStation(uint16_t ls) { char sName[BUFLEN], sUrl[BUFLEN]; int sOvol; @@ -584,9 +591,10 @@ void Config::loadStation(uint16_t ls) { if (ls > store.countStation) { ls = 1; } - File playlist = SPIFFS.open(REAL_PLAYL, "r"); + sdog.takeMutex(); + File playlist = SDPLFS()->open(REAL_PLAYL, "r"); - File index = SPIFFS.open(REAL_INDEX, "r"); + File index = SDPLFS()->open(REAL_INDEX, "r"); index.seek((ls - 1) * 4, SeekSet); uint32_t pos; @@ -603,11 +611,13 @@ void Config::loadStation(uint16_t ls) { setLastStation(ls); } playlist.close(); + sdog.giveMutex(); } char * Config::stationByNum(uint16_t num){ - File playlist = SPIFFS.open(REAL_PLAYL, "r"); - File index = SPIFFS.open(REAL_INDEX, "r"); + sdog.takeMutex(); + File playlist = SDPLFS()->open(REAL_PLAYL, "r"); + File index = SDPLFS()->open(REAL_INDEX, "r"); index.seek((num - 1) * 4, SeekSet); uint32_t pos; memset(_stationBuf, 0, BUFLEN/2); @@ -616,6 +626,7 @@ char * Config::stationByNum(uint16_t num){ playlist.seek(pos, SeekSet); strncpy(_stationBuf, playlist.readStringUntil('\t').c_str(), BUFLEN/2); playlist.close(); + sdog.giveMutex(); return _stationBuf; } @@ -626,8 +637,10 @@ uint8_t Config::fillPlMenu(int from, uint8_t count, bool fromNextion) { if (store.countStation == 0) { return 0; } - File playlist = SPIFFS.open(REAL_PLAYL, "r"); - File index = SPIFFS.open(REAL_INDEX, "r"); + sdog.takeMutex(); + File playlist = SDPLFS()->open(REAL_PLAYL, "r"); + File index = SDPLFS()->open(REAL_INDEX, "r"); + sdog.giveMutex(); while (true) { if (ls < 1) { ls++; @@ -639,15 +652,19 @@ uint8_t Config::fillPlMenu(int from, uint8_t count, bool fromNextion) { continue; } if (!finded) { + sdog.takeMutex(); index.seek((ls - 1) * 4, SeekSet); uint32_t pos; index.readBytes((char *) &pos, 4); finded = true; index.close(); playlist.seek(pos, SeekSet); + sdog.giveMutex(); } while (playlist.available()) { + sdog.takeMutex(); String stationName = playlist.readStringUntil('\n'); + sdog.giveMutex(); stationName = stationName.substring(0, stationName.indexOf('\t')); if(config.store.numplaylist) stationName = String(from+c)+" "+stationName; if(!fromNextion) display.printPLitem(c, stationName.c_str()); @@ -660,7 +677,7 @@ uint8_t Config::fillPlMenu(int from, uint8_t count, bool fromNextion) { break; } return c; - playlist.close(); + sdog.takeMutex();playlist.close();sdog.giveMutex(); } bool Config::parseCSV(const char* line, char* name, char* url, int &ovol) { diff --git a/yoRadio/src/core/config.h b/yoRadio/src/core/config.h index 2efe998..dce2655 100644 --- a/yoRadio/src/core/config.h +++ b/yoRadio/src/core/config.h @@ -35,6 +35,10 @@ #define REAL_INDEX getMode()==PM_WEB?INDEX_PATH:INDEX_SD_PATH #define MAX_PLAY_MODE 1 + +#if SDC_CS!=255 + #define USE_SD +#endif enum playMode_e : uint8_t { PM_WEB=0, PM_SDCARD=1 }; enum cardStatus_e : uint8_t { CS_NONE=0, CS_PRESENT=1, CS_MOUNTED=2, CS_EJECTED=3 }; enum BitrateFormat { BF_UNCNOWN, BF_MP3, BF_AAC, BF_FLAC, BF_OGG, BF_WAV }; @@ -164,7 +168,6 @@ class Config { bool sdSnuffle; bool emptyFS; bool SDinit; - bool mountSDbusy; public: Config() {}; void save(); @@ -194,8 +197,12 @@ class Config { void setBitrateFormat(BitrateFormat fmt) { configFmt = fmt; } void initPlaylist(); void indexPlaylist(); - void initSDPlaylist(bool doIndex = true); - void indexSDPlaylist(); + #ifdef USE_SD + void initSDPlaylist(bool doIndex = true); + void indexSDPlaylist(); + void changeMode(int newmode=-1); + void checkSD(); + #endif uint8_t fillPlMenu(int from, uint8_t count, bool fromNextion=false); char * stationByNum(uint16_t num); void setTimezone(int8_t tzh, int8_t tzm); @@ -207,29 +214,32 @@ class Config { void bootInfo(); void doSleepW(); void setSnuffle(bool sn); - void changeMode(int newmode=-1); uint8_t getMode() { return store.play_mode & 0b11; } void initPlaylistMode(); - void checkSD(); cardStatus_e getSDStatus(){ return _cardStatus; }; void clearCardStatus() { if(_cardStatus!=CS_NONE) _cardStatus=CS_NONE; } bool spiffsCleanup(); + FS* SDPLFS(){ return _SDplaylistFS; } private: template int eepromWrite(int ee, const T& value); template int eepromRead(int ee, T& value); cardStatus_e _cardStatus; bool _bootDone; + FS* _SDplaylistFS; void setDefaults(); Ticker _sleepTimer; static void doSleep(); uint16_t color565(uint8_t r, uint8_t g, uint8_t b); - void listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels); + #ifdef USE_SD + void listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels); + bool _sdCardIsConnected(); + void _mountSD(); + bool _sdBegin(); + #endif bool checkNoMedia(const char* path); void _initHW(); bool _isFSempty(); - bool _sdCardIsConnected(); - void _mountSD(); - bool _sdBegin(); + char _stationBuf[BUFLEN/2]; }; diff --git a/yoRadio/src/core/controls.cpp b/yoRadio/src/core/controls.cpp index 5eeb5dc..c3f64f2 100644 --- a/yoRadio/src/core/controls.cpp +++ b/yoRadio/src/core/controls.cpp @@ -503,10 +503,12 @@ void onBtnClick(int id) { } break; } + #ifdef USE_SD case EVT_BTNMODE: { config.changeMode(); break; } + #endif default: break; } } diff --git a/yoRadio/src/core/display.cpp b/yoRadio/src/core/display.cpp index e9d4b82..946c388 100644 --- a/yoRadio/src/core/display.cpp +++ b/yoRadio/src/core/display.cpp @@ -424,6 +424,10 @@ void Display::loop() { if(_bootstring) _bootstring->setText(const_waitForSD); break; } + case SDFILEINDEX: { + if(_mode == SDCHANGE) _nums.setText(request.payload, "%d"); + break; + } case DSPRSSI: if(_rssi){ _setRSSI(request.payload); } if (_heapbar && config.store.audioinfo) _heapbar->setValue(player.isRunning()?player.inBufferFilled():0); break; case PSTART: _layoutChange(true); break; case PSTOP: _layoutChange(false); break; diff --git a/yoRadio/src/core/display.h b/yoRadio/src/core/display.h index a514063..081234f 100644 --- a/yoRadio/src/core/display.h +++ b/yoRadio/src/core/display.h @@ -12,7 +12,7 @@ enum displayMode_e { PLAYER, VOL, STATIONS, NUMBERS, LOST, UPDATING, INFO, SETTI enum pages_e : uint8_t { PG_PLAYER=0, PG_DIALOG=1, PG_PLAYLIST=2 }; //enum dialogType_e : uint8_t { DG_NONE=0, DG_VOLUME=1, DG_LOST=2, DG_UPDATING=3, DG_NEXTION=4 }; -enum displayRequestType_e { BOOTSTRING, NEWMODE, CLOCK, NEWTITLE, NEWSTATION, NEXTSTATION, DRAWPLAYLIST, DRAWVOL, DBITRATE, AUDIOINFO, SHOWVUMETER, DSPRSSI, SHOWWEATHER, NEWWEATHER, PSTOP, PSTART, DSP_START, WAITFORSD }; +enum displayRequestType_e { BOOTSTRING, NEWMODE, CLOCK, NEWTITLE, NEWSTATION, NEXTSTATION, DRAWPLAYLIST, DRAWVOL, DBITRATE, AUDIOINFO, SHOWVUMETER, DSPRSSI, SHOWWEATHER, NEWWEATHER, PSTOP, PSTART, DSP_START, WAITFORSD, SDFILEINDEX }; struct requestParams_t { displayRequestType_e type; diff --git a/yoRadio/src/core/netserver.cpp b/yoRadio/src/core/netserver.cpp index 7c83589..9d291f6 100644 --- a/yoRadio/src/core/netserver.cpp +++ b/yoRadio/src/core/netserver.cpp @@ -10,11 +10,19 @@ #include "mqtt.h" #include "controls.h" #include +#include "spidog.h" #ifndef MIN_MALLOC #define MIN_MALLOC 24112 #endif +#ifdef USE_SD + #define CARDLOCK() sdog.tm() + #define CARDUNLOCK() sdog.gm() +#else + #define CARDLOCK() {} + #define CARDUNLOCK() {} +#endif //#define CORS_DEBUG NetServer netserver; @@ -152,17 +160,33 @@ void NetServer::beginUpload(AsyncWebServerRequest *request) { } size_t NetServer::chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t index){ - File requiredfile = SPIFFS.open(netserver.chunkedPathBuffer, "r"); + File requiredfile; + bool sdpl = strcmp(netserver.chunkedPathBuffer, PLAYLIST_SD_PATH) == 0; + if(sdpl){ + CARDLOCK(); + requiredfile = config.SDPLFS()->open(netserver.chunkedPathBuffer, "r"); + CARDUNLOCK(); + }else{ + requiredfile = SPIFFS.open(netserver.chunkedPathBuffer, "r"); + } if (!requiredfile) return 0; + if(sdpl) CARDLOCK(); size_t filesize = requiredfile.size(); + if(sdpl) CARDUNLOCK(); size_t needread = filesize - index; - if (!needread) return 0; + if (!needread) { + if(sdpl) { CARDLOCK(); requiredfile.close(); CARDUNLOCK(); } + return 0; + } size_t canread = (needread > maxLen) ? maxLen : needread; DBGVB("[%s] seek to %d in %s and read %d bytes with maxLen=%d", __func__, index, netserver.chunkedPathBuffer, canread, maxLen); + if(sdpl) CARDLOCK(); requiredfile.seek(index, SeekSet); + //vTaskDelay(1); requiredfile.read(buffer, canread); index += canread; if (requiredfile) requiredfile.close(); + if(sdpl) CARDUNLOCK(); return canread; } @@ -204,10 +228,12 @@ void NetServer::processQueue(){ switch (request.type) { case PLAYLIST: getPlaylist(clientId); break; case PLAYLISTSAVED: { + #ifdef USE_SD if(config.getMode()==PM_SDCARD) { // config.indexSDPlaylist(); config.initSDPlaylist(); } + #endif if(config.getMode()==PM_WEB){ config.indexPlaylist(); config.initPlaylist(); @@ -268,7 +294,9 @@ void NetServer::processQueue(){ case BALANCE: sprintf (wsbuf, "{\"balance\": %d}", config.store.balance); break; case SDINIT: sprintf (wsbuf, "{\"sdinit\": %d}", SDC_CS!=255); break; case GETPLAYERMODE: sprintf (wsbuf, "{\"playermode\": \"%s\"}", config.getMode()==PM_SDCARD?"modesd":"modeweb"); break; - case CHANGEMODE: config.changeMode(newConfigMode); return; break; + #ifdef USE_SD + case CHANGEMODE: config.changeMode(newConfigMode); return; break; + #endif default: break; } if (strlen(wsbuf) > 0) { @@ -685,6 +713,10 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { xQueueSend(nsQueue, &nsrequest, portMAX_DELAY); } +void NetServer::resetQueue(){ + xQueueReset(nsQueue); +} + String processor(const String& var) { // %Templates% if (var == "ACTION") return (network.status == CONNECTED && !config.emptyFS)?"webboard":""; if (var == "UPLOADWIFI") return (network.status == CONNECTED)?" hidden":""; @@ -698,8 +730,8 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, if(filename!="tempwifi.csv"){ if(SPIFFS.exists(PLAYLIST_PATH)) SPIFFS.remove(PLAYLIST_PATH); if(SPIFFS.exists(INDEX_PATH)) SPIFFS.remove(INDEX_PATH); - if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_PATH); - if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_PATH); + if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_SD_PATH); + if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); config.clearCardStatus(); } freeSpace = (float)SPIFFS.totalBytes()/100*68-SPIFFS.usedBytes(); diff --git a/yoRadio/src/core/netserver.h b/yoRadio/src/core/netserver.h index 6465775..6589505 100644 --- a/yoRadio/src/core/netserver.h +++ b/yoRadio/src/core/netserver.h @@ -66,6 +66,7 @@ class NetServer { #if IR_PIN!=255 void irToWs(const char* protocol, uint64_t irvalue); void irValsToWs(); + void resetQueue(); #endif private: requestType_e request; diff --git a/yoRadio/src/core/network.cpp b/yoRadio/src/core/network.cpp index afee85e..90ede32 100644 --- a/yoRadio/src/core/network.cpp +++ b/yoRadio/src/core/network.cpp @@ -47,8 +47,8 @@ void ticks() { netserver.setRSSI(WiFi.RSSI()); netserver.requestOnChange(NRSSI, 0); display.putRequest(DSPRSSI, netserver.getRSSI()); -#if SDC_CS!=255 - if(!config.mountSDbusy) player.sendCommand({PR_CHECKSD, 0}); +#ifdef USE_SD + if(display.mode()!=SDCHANGE) player.sendCommand({PR_CHECKSD, 0}); #endif } } diff --git a/yoRadio/src/core/options.h b/yoRadio/src/core/options.h index e94a35a..7968230 100644 --- a/yoRadio/src/core/options.h +++ b/yoRadio/src/core/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define YOVERSION "0.9.220" +#define YOVERSION "0.9.235" /******************************************************* DO NOT EDIT THIS FILE. @@ -311,6 +311,9 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti #ifndef SD_AUTOPLAY #define SD_AUTOPLAY true // auto play from SD card when inserted #endif +#ifndef SD_MAX_LEVELS + #define SD_MAX_LEVELS 3 // search depth for files on the SD card +#endif /* *** ST7735 display submodel *** INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html diff --git a/yoRadio/src/core/player.cpp b/yoRadio/src/core/player.cpp index ecbd048..9571270 100644 --- a/yoRadio/src/core/player.cpp +++ b/yoRadio/src/core/player.cpp @@ -139,10 +139,12 @@ void Player::loop() { Audio::setVolume(volToI2S(requestP.payload)); break; } + #ifdef USE_SD case PR_CHECKSD: { config.checkSD(); break; } + #endif default: break; } } @@ -173,7 +175,7 @@ void Player::_play(uint16_t stationId) { setError(""); remoteStationName = false; config.setDspOn(1); - display.putRequest(PSTOP); + //display.putRequest(PSTOP); setOutputPins(false); config.setTitle(config.getMode()==PM_WEB?const_PlConnect:""); config.station.bitrate=0; diff --git a/yoRadio/src/core/spidog.cpp b/yoRadio/src/core/spidog.cpp index 2a59aeb..caab018 100644 --- a/yoRadio/src/core/spidog.cpp +++ b/yoRadio/src/core/spidog.cpp @@ -7,19 +7,20 @@ SPIDog::SPIDog() { } bool SPIDog::begin(){ - _spiMutex = xSemaphoreCreateMutex(); - return (_spiMutex != NULL); + if(_spiMutex==NULL){ + _spiMutex = xSemaphoreCreateMutex(); + if(_spiMutex==NULL) return false; + } + return true; } bool SPIDog::takeMutex(){ if(_spiMutex == NULL) { return false; } - if(xSemaphoreTake(_spiMutex, SDOG_PORT_DELAY) == pdTRUE){ - _busy = true; - return true; - } - return false; + do { } while (xSemaphoreTake(_spiMutex, portMAX_DELAY) != pdPASS); + _busy = true; + return true; } void SPIDog::giveMutex(){ @@ -27,6 +28,13 @@ void SPIDog::giveMutex(){ _busy = false; } +bool SPIDog::canTake(){ + if(_spiMutex == NULL) { + return false; + } + return xSemaphoreTake(_spiMutex, 0) == pdPASS; +} + bool SPIDog::breakMutex(uint8_t ticks){ if(!_busy){ giveMutex(); diff --git a/yoRadio/src/core/spidog.h b/yoRadio/src/core/spidog.h index 6d5f601..990e059 100644 --- a/yoRadio/src/core/spidog.h +++ b/yoRadio/src/core/spidog.h @@ -17,6 +17,7 @@ class SPIDog { bool begin(); bool takeMutex(); void giveMutex(); + bool canTake(); bool breakMutex(uint8_t ticks=5); bool busy() { return _busy; } bool tm() { return takeMutex(); }