diff --git a/README.md b/README.md index 0735f31..a2fbbb5 100644 --- a/README.md +++ b/README.md @@ -141,11 +141,11 @@ Rotation of the display: --- ## Quick start -
+
- Arduino IDE version 2.x.x is not supported. Use Arduino IDE 1.8.19 - ESP32 core version 2.0.0 or higher is [required](https://github.com/espressif/arduino-esp32)! -- ESP32 core version 3.x.x or higher is not supported (yet)! + 1. Generate a myoptions.h file for your hardware configuration using [this tool](https://e2002.github.io/docs/myoptions-generator.html). 2. Put myoptions.h file next to yoRadio.ino. 3. Replace file Arduino/libraries/Adafruit_GFX_Library/glcdfont.c with file [yoRadio/fonts/glcdfont.c](yoRadio/fonts/glcdfont.c) @@ -234,6 +234,15 @@ Work is in progress... --- ## Version history +#### v0.9.368 +- SD Card - optimization and bug fixes +- Config - improvements and bug fixes +- Added stream format display in the web interface **!!! A full update is required, including SPIFFS Data !!!** + *(Alternatively, upload the new `style.css.gz` and `script.js.gz` files via the web interface.)* +- The content of `yoRadio.ino` has been moved to `src/main.cpp` +- [www|uart|telnet] new command: `reset` - resets settings to default values. [More details](https://github.com/e2002/yoradio/wiki/List-of-available-commands-(UART-telnet-GET-POST)) +- Fixed compilation error: `'ets_printf' was not declared in this scope` + #### v0.9.351 - fixed freezing when loading without plugins in some configurations "running dots" @@ -249,7 +258,7 @@ Work is in progress... More details can be found in the comments within the `yoRadio/src/pluginsManager/pluginsManager.h` file and at [here](https://github.com/e2002/yoradio/blob/main/yoRadio/src/pluginsManager/README.md). Additional examples are provided in the `examples/plugins` folder. **Backward compatibility:** The old method of adding plugins will remain functional for some time in future versions but will eventually be deprecated and removed. - + #### v0.9.342b - fixed compilation error for OLED displays diff --git a/images/board4.jpg b/images/board4.jpg new file mode 100644 index 0000000..28c0c0c Binary files /dev/null and b/images/board4.jpg differ diff --git a/images/board4ru.jpg b/images/board4ru.jpg new file mode 100644 index 0000000..4602403 Binary files /dev/null and b/images/board4ru.jpg differ diff --git a/yoRadio/data/www/script.js.gz b/yoRadio/data/www/script.js.gz index eb03640..de669c9 100644 Binary files a/yoRadio/data/www/script.js.gz and b/yoRadio/data/www/script.js.gz differ diff --git a/yoRadio/data/www/style.css.gz b/yoRadio/data/www/style.css.gz index 07d046f..01bbd1a 100644 Binary files a/yoRadio/data/www/style.css.gz and b/yoRadio/data/www/style.css.gz differ diff --git a/yoRadio/src/AsyncWebServer/AsyncWebSocket.cpp b/yoRadio/src/AsyncWebServer/AsyncWebSocket.cpp index f85952b..1fe20ae 100644 --- a/yoRadio/src/AsyncWebServer/AsyncWebSocket.cpp +++ b/yoRadio/src/AsyncWebServer/AsyncWebSocket.cpp @@ -31,6 +31,7 @@ //https://github.com/me-no-dev/ESPAsyncWebServer/issues/1410 #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) #include "mbedtls/compat-2.x.h" +#include "rom/ets_sys.h" #endif #define MAX_PRINTF_LEN 64 diff --git a/yoRadio/src/audioI2S/Audio.cpp b/yoRadio/src/audioI2S/Audio.cpp index d57f459..7fb0d72 100644 --- a/yoRadio/src/audioI2S/Audio.cpp +++ b/yoRadio/src/audioI2S/Audio.cpp @@ -2447,9 +2447,10 @@ bool Audio::playChunk() { //--------------------------------------------------------------------------------------------------------------------- void Audio::loop() { - - if(!m_f_running) return; - + if(!m_f_running) { + vTaskDelay(2); + return; + } if(m_playlistFormat != FORMAT_M3U8){ // normal process switch(getDatamode()){ case AUDIO_LOCALFILE: diff --git a/yoRadio/src/core/audiohandlers.h b/yoRadio/src/core/audiohandlers.h index bae6786..eb9231f 100644 --- a/yoRadio/src/core/audiohandlers.h +++ b/yoRadio/src/core/audiohandlers.h @@ -119,10 +119,10 @@ void audio_eof_stream(const char *info){ player.sendCommand({PR_STOP, 0}); if(!player.resumeAfterUrl) return; if (config.getMode()==PM_WEB){ - player.sendCommand({PR_PLAY, config.store.lastStation}); + player.sendCommand({PR_PLAY, config.lastStation()}); }else{ player.setResumeFilePos( config.sdResumePos==0?0:config.sdResumePos-player.sd_min); - player.sendCommand({PR_PLAY, config.store.lastStation}); + player.sendCommand({PR_PLAY, config.lastStation()}); } } diff --git a/yoRadio/src/core/config.cpp b/yoRadio/src/core/config.cpp index 312c0ef..7386541 100644 --- a/yoRadio/src/core/config.cpp +++ b/yoRadio/src/core/config.cpp @@ -1,5 +1,5 @@ #include "config.h" -#include + //#include #include "display.h" #include "player.h" @@ -8,6 +8,8 @@ #ifdef USE_SD #include "sdmanager.h" #endif +#include + Config config; #if DSP_HSPI || TS_HSPI || VS_HSPI @@ -20,7 +22,9 @@ void u8fix(char *src){ } bool Config::_isFSempty() { - const char* reqiredFiles[] = {"dragpl.js.gz","elogo.png","elogo84.png","index.html","ir.css.gz","ir.html","ir.js.gz","script.js.gz","settings.css.gz","settings.html","style.css.gz","update.html"}; + const char* reqiredFiles[] = {"dragpl.js.gz","elogo.png","elogo84.png","index.html", + "ir.css.gz","ir.html","ir.js.gz","script.js.gz", + "settings.css.gz","settings.html","style.css.gz","update.html"}; const uint8_t reqiredFilesSize = 12; char fullpath[28]; for (uint8_t i=0; iCONFIG_VERSION) store.version=1; + while(store.version!=CONFIG_VERSION) _setupVersion(); + BOOTLOG("CONFIG_VERSION\t%d", store.version); store.play_mode = store.play_mode & 0b11; + if(store.play_mode>1) store.play_mode=PM_WEB; _initHW(); - //if (!SPIFFS.begin(false, "/spiffs", 30)) { if (!SPIFFS.begin(true)) { Serial.println("##[ERROR]#\tSPIFFS Mount Failed"); return; } BOOTLOG("SPIFFS mounted"); - //emptyFS = !SPIFFS.exists("/www/index.html"); emptyFS = _isFSempty(); if(emptyFS) BOOTLOG("SPIFFS is empty!"); ssidsCount = 0; - //!!_cardStatus = CS_NONE; #ifdef USE_SD _SDplaylistFS = getMode()==PM_SDCARD?&sdman:(true?&SPIFFS:_SDplaylistFS); #else _SDplaylistFS = &SPIFFS; #endif - //if(SDC_CS!=255) randomSeed(analogRead(SDC_CS)); - randomSeed(esp_random()); - backupSDStation = 0; - //checkSD(); _bootDone=false; - //bootInfo(); +} + +void Config::_setupVersion(){ + uint16_t currentVersion = store.version; + switch(currentVersion){ + case 1: + break; + default: + break; + } + currentVersion++; + saveValue(&store.version, currentVersion); } #ifdef USE_SD -/* -void Config::checkSD(){ - cardStatus_e prevCardStatus = _cardStatus; - if(sdman.cardPresent()){ - if(_cardStatus==CS_NONE || _cardStatus==CS_PRESENT || _cardStatus==CS_EJECTED) { - _cardStatus=CS_PRESENT; - }else{ - _cardStatus=CS_MOUNTED; - } - if(_cardStatus==CS_PRESENT && getMode()==PM_WEB && SD_AUTOPLAY && prevCardStatus==CS_EJECTED) config.changeMode(PM_SDCARD); - }else{ - if(_cardStatus==CS_MOUNTED || _cardStatus==CS_PRESENT || _cardStatus==CS_EJECTED){ - if(_cardStatus!=CS_EJECTED && getMode()==PM_SDCARD && SD_AUTOPLAY) config.changeMode(PM_WEB); - _cardStatus=CS_EJECTED; - } - backupSDStation = 0; - } -} -*/ + void Config::changeMode(int newmode){ if(SDC_CS==255) return; + if(getMode()==PM_SDCARD) { + sdResumePos = player.getFilePos(); + } if(network.status==SOFT_AP || display.mode()==LOST){ - store.play_mode=PM_SDCARD; - save(); + saveValue(&store.play_mode, static_cast(PM_SDCARD)); delay(50); ESP.restart(); } - if(!sdman.ready) { - sdman.mount(); - if(!sdman.ready){ + if(!sdman.ready && newmode!=PM_WEB) { + if(!sdman.start()){ Serial.println("##[ERROR]#\tSD Not Found"); netserver.requestOnChange(GETPLAYERMODE, 0); + sdman.stop(); return; } } - if(getMode()==PM_SDCARD) store.lastStation = config.backupLastStation; if(newmode<0){ store.play_mode++; - if(getMode() > MAX_PLAY_MODE){ - store.play_mode=0; - } + if(getMode() > MAX_PLAY_MODE) store.play_mode=0; }else{ store.play_mode=(playMode_e)newmode; } - save(); + saveValue(&store.play_mode, store.play_mode, true, true); _SDplaylistFS = getMode()==PM_SDCARD?&sdman:(true?&SPIFFS:_SDplaylistFS); - if(getMode()==PM_SDCARD && sdman.status()!=CS_MOUNTED){ + if(getMode()==PM_SDCARD){ display.putRequest(NEWMODE, SDCHANGE); while(display.mode()!=SDCHANGE) delay(10); delay(50); } - //if(getMode()==PM_WEB) player.setResumeFilePos(0); - if((getMode()==PM_WEB && network.status==SDREADY)) ESP.restart(); + if(getMode()==PM_WEB) { + if(network.status==SDREADY) ESP.restart(); + sdman.stop(); + } initPlaylistMode(); - if (store.smartstart == 1) player.sendCommand({PR_PLAY, store.lastStation}); - //else - // player.sendCommand({PR_STOP, 0}); + if (store.smartstart == 1) player.sendCommand({PR_PLAY, getMode()==PM_WEB?store.lastStation:store.lastSdStation}); netserver.resetQueue(); netserver.requestOnChange(GETPLAYERMODE, 0); netserver.requestOnChange(GETMODE, 0); @@ -152,19 +145,19 @@ void Config::changeMode(int newmode){ display.putRequest(NEWSTATION); } -void Config::initSDPlaylist(bool doIndex) { +void Config::initSDPlaylist() { store.countStation = 0; - doIndex = !sdman.exists(INDEX_SD_PATH); + bool doIndex = !sdman.exists(INDEX_SD_PATH); if(doIndex) sdman.indexSDPlaylist(); 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; + lastStation(_randomStation()); + sdResumePos = 0; } index.close(); - save(); + saveValue(&store.countStation, store.countStation, true, true); } } @@ -179,41 +172,44 @@ bool Config::spiffsCleanup(){ } void Config::initPlaylistMode(){ - sdResumePos = 0; - //SDinit = false; + uint16_t _lastStation = 0; #ifdef USE_SD - if(!sdman.init()){ - store.play_mode=PM_WEB; - Serial.println("SD Mount Failed"); - changeMode(PM_WEB); - }else{ - Serial.println("SD Mounted"); - if(getMode()==PM_SDCARD) { - if(sdman.status()!=CS_MOUNTED){ - sdman.status(CS_MOUNTED); + if(getMode()==PM_SDCARD){ + if(!sdman.start()){ + store.play_mode=PM_WEB; + Serial.println("SD Mount Failed"); + changeMode(PM_WEB); + _lastStation = store.lastStation; + }else{ + if(_bootDone) Serial.println("SD Mounted"); else BOOTLOG("SD Mounted"); if(_bootDone) Serial.println("Waiting for SD card indexing..."); else BOOTLOG("Waiting for SD card indexing..."); initSDPlaylist(); - }else{ - initSDPlaylist(false); - if(backupSDStation==0) { - store.lastStation = random(1, store.countStation); - backupSDStation = store.lastStation; - }else store.lastStation = backupSDStation; - } + if(_bootDone) Serial.println("done"); else BOOTLOG("done"); + _lastStation = store.lastSdStation; + if(_lastStation>store.countStation && store.countStation>0){ + _lastStation=1; + } + if(_lastStation==0) { + _lastStation = _randomStation(); + } } - //SDinit = true; + }else{ + Serial.println("done"); + _lastStation = store.lastStation; } #else //ifdef USE_SD store.play_mode=PM_WEB; + _lastStation = store.lastStation; #endif if(getMode()==PM_WEB && !emptyFS) initPlaylist(); - - if (store.lastStation == 0 && store.countStation > 0) { - store.lastStation = getMode()==PM_WEB?1:random(1, store.countStation); + log_i("%d" ,_lastStation); + if (_lastStation == 0 && store.countStation > 0) { + _lastStation = getMode()==PM_WEB?1:_randomStation(); } - save(); + lastStation(_lastStation); + saveValue(&store.play_mode, store.play_mode, true, true); _bootDone = true; - loadStation(store.lastStation); + loadStation(_lastStation); } void Config::_initHW(){ @@ -289,8 +285,16 @@ template int Config::eepromRead(int ee, T& value) { return i; } +void Config::reset(){ + setDefaults(); + eepromWrite(EEPROM_START, store); + delay(100); + ESP.restart(); +} + void Config::setDefaults() { store.config_set = 4262; + store.version = CONFIG_VERSION; store.volume = 12; store.balance = 0; store.trebble = 0; @@ -320,10 +324,13 @@ void Config::setDefaults() { store.showweather=false; strlcpy(store.weatherlat,"55.7512", 10); strlcpy(store.weatherlon,"37.6184", 10); - strlcpy(store.weatherkey,"", 64); + strlcpy(store.weatherkey,"", WEATHERKEY_LENGTH); + store._reserved = 0; + store.lastSdStation = 0; + store.sdsnuffle = false; store.volsteps = 1; store.encacc = 200; - store.play_mode = 0b100; + store.play_mode = 0; store.irtlp = 35; store.btnpullup = true; store.btnlongpress = 200; @@ -339,35 +346,21 @@ void Config::setDefaults() { } void Config::setTimezone(int8_t tzh, int8_t tzm) { - store.tzHour = tzh; - store.tzMin = tzm; - save(); + saveValue(&store.tzHour, tzh, false); + saveValue(&store.tzMin, tzm); } void Config::setTimezoneOffset(uint16_t tzo) { - store.timezoneOffset = tzo; - save(); + saveValue(&store.timezoneOffset, tzo); } uint16_t Config::getTimezoneOffset() { return 0; // TODO } -void Config::save() { - uint16_t ls = store.lastStation; - uint8_t pm = store.play_mode; - if(getMode()==PM_SDCARD) store.lastStation = backupLastStation; - if(getMode()==PM_WEB) backupLastStation = store.lastStation; - bitWrite(store.play_mode, 2, sdSnuffle); - eepromWrite(EEPROM_START, store); - store.lastStation = ls; - store.play_mode = pm; -} - void Config::setSnuffle(bool sn){ - sdSnuffle=sn; - save(); - if(sdSnuffle) player.next(); + saveValue(&store.sdsnuffle, sn); + if(store.sdsnuffle) player.next(); } #if IR_PIN!=255 @@ -377,8 +370,7 @@ void Config::saveIR(){ #endif void Config::saveVolume(){ - EEPROM.write(EEPROM_START + sizeof(store.config_set), store.volume); - EEPROM.commit(); + saveValue(&store.volume, store.volume, true, true); } uint8_t Config::setVolume(uint8_t val) { @@ -389,39 +381,31 @@ uint8_t Config::setVolume(uint8_t val) { } void Config::setTone(int8_t bass, int8_t middle, int8_t trebble) { - store.bass = bass; - store.middle = middle; - store.trebble = trebble; - save(); + saveValue(&store.bass, bass, false); + saveValue(&store.middle, middle, false); + saveValue(&store.trebble, trebble); } void Config::setSmartStart(uint8_t ss) { - if (store.smartstart < 2) { - store.smartstart = ss; - save(); - } + saveValue(&store.smartstart, ss); } void Config::setBalance(int8_t balance) { - store.balance = balance; - save(); + saveValue(&store.balance, balance); } uint8_t Config::setLastStation(uint16_t val) { - store.lastStation = val; - save(); + lastStation(val); return store.lastStation; } uint8_t Config::setCountStation(uint16_t val) { - store.countStation = val; - save(); + saveValue(&store.countStation, val); return store.countStation; } uint8_t Config::setLastSSID(uint8_t val) { - store.lastSSID = val; - save(); + saveValue(&store.lastSSID, val); return store.lastSSID; } @@ -466,7 +450,7 @@ void Config::initPlaylist() { File index = SPIFFS.open(INDEX_PATH, "r"); store.countStation = index.size() / 4; index.close(); - save(); + saveValue(&store.countStation, store.countStation, true, true); } } @@ -484,13 +468,10 @@ void Config::loadStation(uint16_t ls) { ls = 1; } File playlist = SDPLFS()->open(REAL_PLAYL, "r"); - File index = SDPLFS()->open(REAL_INDEX, "r"); index.seek((ls - 1) * 4, SeekSet); uint32_t pos; - index.readBytes((char *) &pos, 4); - index.close(); playlist.seek(pos, SeekSet); if (parseCSV(playlist.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) { @@ -702,26 +683,29 @@ void Config::setBrightness(bool dosave){ if(!store.dspon && dosave) { display.wakeup(); } - //analogWrite(BRIGHTNESS_PIN, config.store.dspon?map(store.brightness, 0, 100, 0, 255):0); analogWrite(BRIGHTNESS_PIN, map(store.brightness, 0, 100, 0, 255)); if(!store.dspon) store.dspon = true; - if(dosave) save(); + if(dosave){ + saveValue(&store.brightness, store.brightness, false, true); + saveValue(&store.dspon, store.dspon, true, true); + } #endif #ifdef USE_NEXTION -// if(!store.dspon && dosave) { - nextion.wake(); -// } + nextion.wake(); char cmd[15]; snprintf(cmd, 15, "dims=%d", store.brightness); nextion.putcmd(cmd); if(!store.dspon) store.dspon = true; - if(dosave) save(); + if(dosave){ + saveValue(&store.brightness, store.brightness, false, true); + saveValue(&store.dspon, store.dspon, true, true); + } #endif } void Config::setDspOn(bool dspon){ store.dspon = dspon; - save(); + saveValue(&store.dspon, store.dspon, true, true); #ifdef USE_NEXTION if(!dspon) nextion.sleep(); else nextion.wake(); @@ -796,8 +780,10 @@ void Config::bootInfo() { BOOTLOG("flipscreen:\t%s", store.flipscreen?"true":"false"); BOOTLOG("invertdisplay:\t%s", store.invertdisplay?"true":"false"); BOOTLOG("showweather:\t%s", store.showweather?"true":"false"); - BOOTLOG("buttons:\tleft=%d, center=%d, right=%d, up=%d, down=%d, mode=%d, pullup=%s", BTN_LEFT, BTN_CENTER, BTN_RIGHT, BTN_UP, BTN_DOWN, BTN_MODE, BTN_INTERNALPULLUP?"true":"false"); - BOOTLOG("encoders:\tl1=%d, b1=%d, r1=%d, pullup=%s, l2=%d, b2=%d, r2=%d, pullup=%s", ENC_BTNL, ENC_BTNB, ENC_BTNR, ENC_INTERNALPULLUP?"true":"false", ENC2_BTNL, ENC2_BTNB, ENC2_BTNR, ENC2_INTERNALPULLUP?"true":"false"); + BOOTLOG("buttons:\tleft=%d, center=%d, right=%d, up=%d, down=%d, mode=%d, pullup=%s", + BTN_LEFT, BTN_CENTER, BTN_RIGHT, BTN_UP, BTN_DOWN, BTN_MODE, BTN_INTERNALPULLUP?"true":"false"); + BOOTLOG("encoders:\tl1=%d, b1=%d, r1=%d, pullup=%s, l2=%d, b2=%d, r2=%d, pullup=%s", + ENC_BTNL, ENC_BTNB, ENC_BTNR, ENC_INTERNALPULLUP?"true":"false", ENC2_BTNL, ENC2_BTNB, ENC2_BTNR, ENC2_INTERNALPULLUP?"true":"false"); BOOTLOG("ir:\t\t%d", IR_PIN); if(SDC_CS!=255) BOOTLOG("SD:\t\t%d", SDC_CS); BOOTLOG("------------------------------------------------"); diff --git a/yoRadio/src/core/config.h b/yoRadio/src/core/config.h index 13811e3..77c5177 100644 --- a/yoRadio/src/core/config.h +++ b/yoRadio/src/core/config.h @@ -4,6 +4,7 @@ #include #include #include +#include //#include "SD.h" #include "options.h" #include "rtcsupport.h" @@ -37,13 +38,15 @@ #define REAL_INDEX getMode()==PM_WEB?INDEX_PATH:INDEX_SD_PATH #define MAX_PLAY_MODE 1 - +#define WEATHERKEY_LENGTH 58 #if SDC_CS!=255 #define USE_SD #endif #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) #define ESP_ARDUINO_3 1 #endif +#define CONFIG_VERSION 1 + enum playMode_e : uint8_t { PM_WEB=0, PM_SDCARD=1 }; enum BitrateFormat { BF_UNCNOWN, BF_MP3, BF_AAC, BF_FLAC, BF_OGG, BF_WAV }; @@ -81,21 +84,21 @@ struct theme_t { }; struct config_t { - unsigned int config_set; //must be 4262 - uint8_t volume; - int8_t balance; - int8_t trebble; - int8_t middle; - int8_t bass; - uint16_t lastStation; - uint16_t countStation; - uint8_t lastSSID; - bool audioinfo; - uint8_t smartstart; - int8_t tzHour; - int8_t tzMin; - uint16_t timezoneOffset; - + uint16_t config_set; //must be 4262 + uint16_t version; + uint8_t volume; + int8_t balance; + int8_t trebble; + int8_t middle; + int8_t bass; + uint16_t lastStation; + uint16_t countStation; + uint8_t lastSSID; + bool audioinfo; + uint8_t smartstart; + int8_t tzHour; + int8_t tzMin; + uint16_t timezoneOffset; bool vumeter; uint8_t softapdelay; bool flipscreen; @@ -111,7 +114,10 @@ struct config_t bool showweather; char weatherlat[10]; char weatherlon[10]; - char weatherkey[64]; + char weatherkey[WEATHERKEY_LENGTH]; + uint16_t _reserved; + uint16_t lastSdStation; + bool sdsnuffle; uint8_t volsteps; uint16_t encacc; uint8_t play_mode; //0 WEB, 1 SD @@ -167,14 +173,10 @@ class Config { uint8_t ssidsCount; uint16_t sleepfor; uint32_t sdResumePos; - uint16_t backupLastStation; - uint16_t backupSDStation; - bool sdSnuffle; bool emptyFS; - bool SDinit; public: Config() {}; - void save(); + //void save(); #if IR_PIN!=255 void saveIR(); #endif @@ -202,10 +204,16 @@ class Config { void initPlaylist(); void indexPlaylist(); #ifdef USE_SD - void initSDPlaylist(bool doIndex = true); - + void initSDPlaylist(); void changeMode(int newmode=-1); #endif + uint16_t lastStation(){ + return getMode()==PM_WEB?store.lastStation:store.lastSdStation; + } + void lastStation(uint16_t newstation){ + if(getMode()==PM_WEB) saveValue(&store.lastStation, newstation); + else saveValue(&store.lastSdStation, newstation); + } uint8_t fillPlMenu(int from, uint8_t count, bool fromNextion=false); char * stationByNum(uint16_t num); void setTimezone(int8_t tzh, int8_t tzm); @@ -217,18 +225,38 @@ class Config { void bootInfo(); void doSleepW(); void setSnuffle(bool sn); - uint8_t getMode() { return store.play_mode & 0b11; } + uint8_t getMode() { return store.play_mode/* & 0b11*/; } void initPlaylistMode(); - + void reset(); bool spiffsCleanup(); FS* SDPLFS(){ return _SDplaylistFS; } #if RTCSUPPORTED bool isRTCFound(){ return _rtcFound; }; #endif + template + size_t getAddr(const T *field) const { + return (size_t)((const uint8_t *)field - (const uint8_t *)&store) + EEPROM_START; + } + template + void saveValue(T *field, const T &value, bool commit=true, bool force=false){ + if(*field == value && !force) return; + *field = value; + size_t address = getAddr(field); + EEPROM.put(address, value); + if(commit) + EEPROM.commit(); + } + void saveValue(char *field, const char *value, size_t N, bool commit=true, bool force=false) { + if (strcmp(field, value) == 0 && !force) return; + strlcpy(field, value, N); + size_t address = getAddr(field); + for (size_t i = 0; i < strlen(field); i++) EEPROM.write(address + i, field[i]); + if(commit) + EEPROM.commit(); + } private: template int eepromWrite(int ee, const T& value); template int eepromRead(int ee, T& value); - bool _bootDone; #if RTCSUPPORTED bool _rtcFound; @@ -238,10 +266,14 @@ class Config { Ticker _sleepTimer; static void doSleep(); uint16_t color565(uint8_t r, uint8_t g, uint8_t b); - + void _setupVersion(); void _initHW(); bool _isFSempty(); - + uint16_t _randomStation(){ + randomSeed(esp_random() ^ millis()); + uint16_t station = random(1, store.countStation); + return station; + } char _stationBuf[BUFLEN/2]; }; @@ -250,5 +282,4 @@ extern Config config; extern SPIClass SPI2; #endif - #endif diff --git a/yoRadio/src/core/controls.cpp b/yoRadio/src/core/controls.cpp index ed8d435..a8c2a7c 100644 --- a/yoRadio/src/core/controls.cpp +++ b/yoRadio/src/core/controls.cpp @@ -555,15 +555,13 @@ void onBtnDoubleClick(int id) { } } void setIRTolerance(uint8_t tl){ - config.store.irtlp=tl; - config.save(); + config.saveValue(&config.store.irtlp, tl); #if IR_PIN!=255 irrecv.setTolerance(config.store.irtlp); #endif } void setEncAcceleration(uint16_t acc){ - config.store.encacc=acc; - config.save(); + config.saveValue(&config.store.encacc, acc); #if ENC_BTNL!=255 encoder.setAcceleration(config.store.encacc); #endif diff --git a/yoRadio/src/core/display.cpp b/yoRadio/src/core/display.cpp index e39e2ff..8c3e31f 100644 --- a/yoRadio/src/core/display.cpp +++ b/yoRadio/src/core/display.cpp @@ -298,7 +298,7 @@ void Display::_swichMode(displayMode_e newmode) { if (newmode == STATIONS) { _pager.setPage( pages[PG_PLAYLIST]); _plcurrent.setText(""); - currentPlItem = config.store.lastStation; + currentPlItem = config.lastStation(); _drawPlaylist(); } diff --git a/yoRadio/src/core/mqtt.cpp b/yoRadio/src/core/mqtt.cpp index f6d7db7..a1180a3 100644 --- a/yoRadio/src/core/mqtt.cpp +++ b/yoRadio/src/core/mqtt.cpp @@ -39,7 +39,7 @@ void mqttPublishStatus() { memset(topic, 0, 140); memset(status, 0, BUFLEN*3); sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "status"); - sprintf(status, "{\"status\": %d, \"station\": %d, \"name\": \"%s\", \"title\": \"%s\", \"on\": %d}", player.status()==PLAYING?1:0, config.store.lastStation, config.station.name, config.station.title, config.store.dspon); + sprintf(status, "{\"status\": %d, \"station\": %d, \"name\": \"%s\", \"title\": \"%s\", \"on\": %d}", player.status()==PLAYING?1:0, config.lastStation(), config.station.name, config.station.title, config.store.dspon); mqttClient.publish(topic, 0, true, status); } } @@ -92,7 +92,7 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties return; } if (strcmp(buf, "start") == 0 || strcmp(buf, "play") == 0) { - player.sendCommand({PR_PLAY, config.store.lastStation}); + player.sendCommand({PR_PLAY, config.lastStation()}); return; } if (strcmp(buf, "boot") == 0 || strcmp(buf, "reboot") == 0) { @@ -113,13 +113,12 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties player.sendCommand({PR_STOP, 0}); //telnet.info(); delay(100); - config.store.smartstart = sst; - config.save(); + config.saveValue(&config.store.smartstart, sst); return; } if (strcmp(buf, "turnon") == 0) { config.setDspOn(1); - if (config.store.smartstart == 1) player.sendCommand({PR_PLAY, config.store.lastStation}); + if (config.store.smartstart == 1) player.sendCommand({PR_PLAY, config.lastStation()}); return; } int volume; diff --git a/yoRadio/src/core/netserver.cpp b/yoRadio/src/core/netserver.cpp index a597c0d..3a80bfd 100644 --- a/yoRadio/src/core/netserver.cpp +++ b/yoRadio/src/core/netserver.cpp @@ -17,7 +17,7 @@ #define MIN_MALLOC 24112 #endif #ifndef NSQ_SEND_DELAY - #define NSQ_SEND_DELAY (TickType_t)100 //portMAX_DELAY? + #define NSQ_SEND_DELAY (TickType_t)100 //portMAX_DELAY? #endif //#define CORS_DEBUG @@ -63,16 +63,16 @@ bool NetServer::begin(bool quiet) { if(config.emptyFS){ webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/html", emptyfs_html, processor); }); webserver.on("/", HTTP_POST, [](AsyncWebServerRequest *request) { - if(request->arg("ssid")!="" && request->arg("pass")!=""){ - char buf[BUFLEN]; - memset(buf, 0, BUFLEN); - snprintf(buf, BUFLEN, "%s\t%s", request->arg("ssid").c_str(), request->arg("pass").c_str()); - request->redirect("/"); - config.saveWifiFromNextion(buf); - return; - } - request->redirect("/"); - ESP.restart(); + if(request->arg("ssid")!="" && request->arg("pass")!=""){ + char buf[BUFLEN]; + memset(buf, 0, BUFLEN); + snprintf(buf, BUFLEN, "%s\t%s", request->arg("ssid").c_str(), request->arg("pass").c_str()); + request->redirect("/"); + config.saveWifiFromNextion(buf); + return; + } + request->redirect("/"); + ESP.restart(); }, handleUploadWeb); }else{ webserver.on("/", HTTP_ANY, handleHTTPArgs); @@ -161,16 +161,16 @@ size_t NetServer::chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t File requiredfile; bool sdpl = strcmp(netserver.chunkedPathBuffer, PLAYLIST_SD_PATH) == 0; if(sdpl){ - requiredfile = config.SDPLFS()->open(netserver.chunkedPathBuffer, "r"); + requiredfile = config.SDPLFS()->open(netserver.chunkedPathBuffer, "r"); }else{ - requiredfile = SPIFFS.open(netserver.chunkedPathBuffer, "r"); + requiredfile = SPIFFS.open(netserver.chunkedPathBuffer, "r"); } if (!requiredfile) return 0; size_t filesize = requiredfile.size(); size_t needread = filesize - index; if (!needread) { - requiredfile.close(); - return 0; + requiredfile.close(); + 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); @@ -187,9 +187,9 @@ void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest strlcpy(chunkedPathBuffer, path, sizeof(chunkedPathBuffer)-1); AsyncWebServerResponse *response; if(doproc) - response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback, processor); + response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback, processor); else - response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback); + response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback); request->send(response); } @@ -208,6 +208,17 @@ void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest #define NS_QUEUE_TICKS 0 #endif +const char *getFormat(BitrateFormat _format) { + switch (_format) { + case BF_MP3: return "MP3"; + case BF_AAC: return "AAC"; + case BF_FLAC: return "FLC"; + case BF_OGG: return "OGG"; + case BF_WAV: return "WAV"; + default: return "bitrate"; + } +} + char wsbuf[BUFLEN * 2]; void NetServer::processQueue(){ if(nsQueue==NULL) return; @@ -218,7 +229,7 @@ void NetServer::processQueue(){ switch (request.type) { case PLAYLIST: getPlaylist(clientId); break; case PLAYLISTSAVED: { - #ifdef USE_SD + #ifdef USE_SD if(config.getMode()==PM_SDCARD) { // config.indexSDPlaylist(); config.initSDPlaylist(); @@ -262,30 +273,76 @@ void NetServer::processQueue(){ break; } case GETMODE: sprintf (wsbuf, "{\"pmode\":\"%s\"}", network.status == CONNECTED ? "player" : "ap"); break; - case GETINDEX: requestOnChange(STATION, clientId); requestOnChange(TITLE, clientId); requestOnChange(VOLUME, clientId); requestOnChange(EQUALIZER, clientId); requestOnChange(BALANCE, clientId); requestOnChange(BITRATE, clientId); requestOnChange(MODE, clientId); requestOnChange(SDINIT, clientId);requestOnChange(GETPLAYERMODE, clientId); if (config.getMode()==PM_SDCARD) { requestOnChange(SDPOS, clientId); requestOnChange(SDLEN, clientId); requestOnChange(SDSNUFFLE, clientId); } return; break; - case GETSYSTEM: sprintf (wsbuf, "{\"sst\":%d,\"aif\":%d,\"vu\":%d,\"softr\":%d}", config.store.smartstart != 2, config.store.audioinfo, config.store.vumeter, config.store.softapdelay); break; - case GETSCREEN: sprintf (wsbuf, "{\"flip\":%d,\"inv\":%d,\"nump\":%d,\"tsf\":%d,\"tsd\":%d,\"dspon\":%d,\"br\":%d,\"con\":%d}", config.store.flipscreen, config.store.invertdisplay, config.store.numplaylist, config.store.fliptouch, config.store.dbgtouch, config.store.dspon, config.store.brightness, config.store.contrast); break; - case GETTIMEZONE: sprintf (wsbuf, "{\"tzh\":%d,\"tzm\":%d,\"sntp1\":\"%s\",\"sntp2\":\"%s\"}", config.store.tzHour, config.store.tzMin, config.store.sntp1, config.store.sntp2); break; - case GETWEATHER: sprintf (wsbuf, "{\"wen\":%d,\"wlat\":\"%s\",\"wlon\":\"%s\",\"wkey\":\"%s\"}", config.store.showweather, config.store.weatherlat, config.store.weatherlon, config.store.weatherkey); break; - case GETCONTROLS: sprintf (wsbuf, "{\"vols\":%d,\"enca\":%d,\"irtl\":%d}", config.store.volsteps, config.store.encacc, config.store.irtlp); break; + case GETINDEX: { + requestOnChange(STATION, clientId); + requestOnChange(TITLE, clientId); + requestOnChange(VOLUME, clientId); + requestOnChange(EQUALIZER, clientId); + requestOnChange(BALANCE, clientId); + requestOnChange(BITRATE, clientId); + requestOnChange(MODE, clientId); + requestOnChange(SDINIT, clientId); + requestOnChange(GETPLAYERMODE, clientId); + if (config.getMode()==PM_SDCARD) { requestOnChange(SDPOS, clientId); requestOnChange(SDLEN, clientId); requestOnChange(SDSNUFFLE, clientId); } + return; + break; + } + case GETSYSTEM: sprintf (wsbuf, "{\"sst\":%d,\"aif\":%d,\"vu\":%d,\"softr\":%d}", + config.store.smartstart != 2, + config.store.audioinfo, + config.store.vumeter, + config.store.softapdelay); + break; + case GETSCREEN: sprintf (wsbuf, "{\"flip\":%d,\"inv\":%d,\"nump\":%d,\"tsf\":%d,\"tsd\":%d,\"dspon\":%d,\"br\":%d,\"con\":%d}", + config.store.flipscreen, + config.store.invertdisplay, + config.store.numplaylist, + config.store.fliptouch, + config.store.dbgtouch, + config.store.dspon, + config.store.brightness, + config.store.contrast); + break; + case GETTIMEZONE: sprintf (wsbuf, "{\"tzh\":%d,\"tzm\":%d,\"sntp1\":\"%s\",\"sntp2\":\"%s\"}", + config.store.tzHour, + config.store.tzMin, + config.store.sntp1, + config.store.sntp2); + break; + case GETWEATHER: sprintf (wsbuf, "{\"wen\":%d,\"wlat\":\"%s\",\"wlon\":\"%s\",\"wkey\":\"%s\"}", + config.store.showweather, + config.store.weatherlat, + config.store.weatherlon, + config.store.weatherkey); + break; + case GETCONTROLS: sprintf (wsbuf, "{\"vols\":%d,\"enca\":%d,\"irtl\":%d}", + config.store.volsteps, + config.store.encacc, + config.store.irtlp); + break; case DSPON: sprintf (wsbuf, "{\"dspontrue\":%d}", 1); break; case STATION: requestOnChange(STATIONNAME, clientId); requestOnChange(ITEM, clientId); break; case STATIONNAME: sprintf (wsbuf, "{\"nameset\": \"%s\"}", config.station.name); break; - case ITEM: sprintf (wsbuf, "{\"current\": %d}", config.store.lastStation); break; + case ITEM: sprintf (wsbuf, "{\"current\": %d}", config.lastStation()); break; case TITLE: sprintf (wsbuf, "{\"meta\": \"%s\"}", config.station.title); telnet.printf("##CLI.META#: %s\n> ", config.station.title); break; case VOLUME: sprintf (wsbuf, "{\"vol\": %d}", config.store.volume); telnet.printf("##CLI.VOL#: %d\n", config.store.volume); break; case NRSSI: sprintf (wsbuf, "{\"rssi\": %d}", rssi); /*rssi = 255;*/ break; - case SDPOS: sprintf (wsbuf, "{\"sdpos\": %d,\"sdend\": %d,\"sdtpos\": %d,\"sdtend\": %d}", player.getFilePos(), player.getFileSize(), player.getAudioCurrentTime(), player.getAudioFileDuration()); break; + case SDPOS: sprintf (wsbuf, "{\"sdpos\": %d,\"sdend\": %d,\"sdtpos\": %d,\"sdtend\": %d}", + player.getFilePos(), + player.getFileSize(), + player.getAudioCurrentTime(), + player.getAudioFileDuration()); + break; case SDLEN: sprintf (wsbuf, "{\"sdmin\": %d,\"sdmax\": %d}", player.sd_min, player.sd_max); break; - case SDSNUFFLE: sprintf (wsbuf, "{\"snuffle\": %d}", config.sdSnuffle); break; - case BITRATE: sprintf (wsbuf, "{\"bitrate\": %d}", config.station.bitrate); break; + case SDSNUFFLE: sprintf (wsbuf, "{\"snuffle\": %d}", config.store.sdsnuffle); break; + case BITRATE: sprintf (wsbuf, "{\"bitrate\": %d, \"format\": \"%s\"}", config.station.bitrate, getFormat(config.configFmt)); break; case MODE: sprintf (wsbuf, "{\"mode\": \"%s\"}", player.status() == PLAYING ? "playing" : "stopped"); telnet.info(); break; case EQUALIZER: sprintf (wsbuf, "{\"bass\": %d, \"middle\": %d, \"trebble\": %d}", config.store.bass, config.store.middle, config.store.trebble); break; 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; #ifdef USE_SD - case CHANGEMODE: config.changeMode(newConfigMode); return; break; + case CHANGEMODE: config.changeMode(newConfigMode); return; break; #endif default: break; } @@ -347,62 +404,54 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client if (strcmp(cmd, "newmode") == 0 ) { newConfigMode = atoi(val); requestOnChange(CHANGEMODE, 0); return; } if (strcmp(cmd, "smartstart") == 0) { uint8_t valb = atoi(val); - config.store.smartstart = valb == 1 ? 1 : 2; - if (!player.isRunning() && config.store.smartstart == 1) config.store.smartstart = 0; - config.save(); + uint8_t ss = valb == 1 ? 1 : 2; + if (!player.isRunning() && ss == 1) ss = 0; + config.setSmartStart(ss); return; } if (strcmp(cmd, "audioinfo") == 0) { - uint8_t valb = atoi(val); - config.store.audioinfo = valb; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.audioinfo, valb); display.putRequest(AUDIOINFO); return; } if (strcmp(cmd, "vumeter") == 0) { - uint8_t valb = atoi(val); - config.store.vumeter = valb; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.vumeter, valb); display.putRequest(SHOWVUMETER); return; } if (strcmp(cmd, "softap") == 0) { uint8_t valb = atoi(val); - config.store.softapdelay = valb; - config.save(); + config.saveValue(&config.store.softapdelay, valb); return; } if (strcmp(cmd, "invertdisplay") == 0) { - uint8_t valb = atoi(val); - config.store.invertdisplay = valb; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.invertdisplay, valb); display.invert(); return; } if (strcmp(cmd, "numplaylist") == 0) { - uint8_t valb = atoi(val); - config.store.numplaylist = valb; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.numplaylist, valb); display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); return; } if (strcmp(cmd, "fliptouch") == 0) { - uint8_t valb = atoi(val); - config.store.fliptouch = valb == 1; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.fliptouch, valb); flipTS(); return; } if (strcmp(cmd, "dbgtouch") == 0) { - uint8_t valb = atoi(val); - config.store.dbgtouch = valb == 1; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.dbgtouch, valb); return; } if (strcmp(cmd, "flipscreen") == 0) { - uint8_t valb = atoi(val); - config.store.flipscreen = valb; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.flipscreen, valb); display.flip(); display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); return; @@ -415,14 +464,13 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client return; } if (strcmp(cmd, "screenon") == 0) { - uint8_t valb = atoi(val); - config.setDspOn(valb == 1); + bool valb = static_cast(atoi(val)); + config.setDspOn(valb); return; } if (strcmp(cmd, "contrast") == 0) { uint8_t valb = atoi(val); - config.store.contrast = valb; - config.save(); + config.saveValue(&config.store.contrast, valb); display.setContrast(); return; } @@ -437,7 +485,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client return; } if (strcmp(cmd, "sntp2") == 0) { - strlcpy(config.store.sntp2, val, 35); + config.saveValue(config.store.sntp2, val, 35, false); return; } if (strcmp(cmd, "sntp1") == 0) { @@ -451,23 +499,20 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client tzdone = true; } if (tzdone) { - //network.requestTimeSync(true); network.forceTimeSync = true; - config.save(); + config.saveValue(config.store.sntp1, val, 35); } return; } if (strcmp(cmd, "volsteps") == 0) { uint8_t valb = atoi(val); - config.store.volsteps = valb; - config.save(); + config.saveValue(&config.store.volsteps, valb); return; } if (strcmp(cmd, "encacceleration") == 0) { uint16_t valb = atoi(val); setEncAcceleration(valb); - config.store.encacc = valb; - config.save(); + config.saveValue(&config.store.encacc, valb); return; } if (strcmp(cmd, "irtlp") == 0) { @@ -476,25 +521,23 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client return; } if (strcmp(cmd, "showweather") == 0) { - uint8_t valb = atoi(val); - config.store.showweather = valb == 1; - config.save(); + bool valb = static_cast(atoi(val)); + config.saveValue(&config.store.showweather, valb); network.trueWeather=false; network.forceWeather = true; display.putRequest(SHOWWEATHER); return; } if (strcmp(cmd, "lat") == 0) { - strlcpy(config.store.weatherlat, val, 10); + config.saveValue(config.store.weatherlat, val, 10, false); return; } if (strcmp(cmd, "lon") == 0) { - strlcpy(config.store.weatherlon, val, 10); + config.saveValue(config.store.weatherlon, val, 10, false); return; } if (strcmp(cmd, "key") == 0) { - strlcpy(config.store.weatherkey, val, 64); - config.save(); + config.saveValue(config.store.weatherkey, val, WEATHERKEY_LENGTH); network.trueWeather=false; display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); return; @@ -502,27 +545,25 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client /* RESETS */ if (strcmp(cmd, "reset") == 0) { if (strcmp(val, "system") == 0) { - config.store.smartstart = 2; - config.store.audioinfo = false; - config.store.vumeter = false; - config.store.softapdelay = 0; - config.save(); + config.saveValue(&config.store.smartstart, (uint8_t)2, false); + config.saveValue(&config.store.audioinfo, false, false); + config.saveValue(&config.store.vumeter, false, false); + config.saveValue(&config.store.softapdelay, (uint8_t)0); display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); requestOnChange(GETSYSTEM, clientId); return; } if (strcmp(val, "screen") == 0) { - config.store.flipscreen = false; + config.saveValue(&config.store.flipscreen, false, false); display.flip(); - config.store.invertdisplay = false; + config.saveValue(&config.store.invertdisplay, false, false); display.invert(); - config.store.dspon = true; + config.saveValue(&config.store.dspon, true, false); config.store.brightness = 100; config.setBrightness(false); - config.store.contrast = 55; + config.saveValue(&config.store.contrast, (uint8_t)55, false); display.setContrast(); - config.store.numplaylist = false; - config.save(); + config.saveValue(&config.store.numplaylist, false); display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); requestOnChange(GETSCREEN, clientId); return; @@ -530,9 +571,8 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client if (strcmp(val, "timezone") == 0) { config.store.tzHour = 3; config.store.tzMin = 0; - strlcpy(config.store.sntp1, "pool.ntp.org", 35); - strlcpy(config.store.sntp2, "0.ru.pool.ntp.org", 35); - config.save(); + config.saveValue(config.store.sntp1, "pool.ntp.org", 35, false); + config.saveValue(config.store.sntp2, "0.ru.pool.ntp.org", 35); configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2); network.forceTimeSync = true; requestOnChange(GETTIMEZONE, clientId); @@ -540,10 +580,9 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client } if (strcmp(val, "weather") == 0) { config.store.showweather = 0; - strlcpy(config.store.weatherlat, "55.7512", 10); - strlcpy(config.store.weatherlon, "37.6184", 10); - strlcpy(config.store.weatherkey, "", 64); - config.save(); + config.saveValue(config.store.weatherlat, "55.7512", 10, false); + config.saveValue(config.store.weatherlon, "37.6184", 10, false); + config.saveValue(config.store.weatherkey, "", WEATHERKEY_LENGTH); network.trueWeather=false; display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); requestOnChange(GETWEATHER, clientId); @@ -569,7 +608,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client config.sdResumePos = 0; if(!player.isRunning()){ player.setResumeFilePos(atoi(val)-player.sd_min); - player.sendCommand({PR_PLAY, config.store.lastStation}); + player.sendCommand({PR_PLAY, config.store.lastSdStation}); }else{ player.setFilePos(atoi(val)-player.sd_min); } @@ -617,7 +656,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client mqttplaylistticker.attach(5, mqttplaylistSend); #endif if (player.isRunning()) { - player.sendCommand({PR_PLAY, -config.store.lastStation}); + player.sendCommand({PR_PLAY, -config.lastStation()}); } return; } @@ -716,21 +755,18 @@ String processor(const String& var) { // %Templates% int freeSpace; void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { if (!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_SD_PATH); - if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); - #ifdef USE_SD - sdman.clearCardStatus(); - #endif + 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_SD_PATH); + if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); } freeSpace = (float)SPIFFS.totalBytes()/100*68-SPIFFS.usedBytes(); request->_tempFile = SPIFFS.open(TMP_PATH , "w"); } if (len) { - if(freeSpace>index+len){ - request->_tempFile.write(data, len); + if(freeSpace>index+len){ + request->_tempFile.write(data, len); } } if (final) { @@ -768,7 +804,12 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp void handleHTTPArgs(AsyncWebServerRequest * request) { if (request->method() == HTTP_GET) { DBGVB("[%s] client ip=%s request of %s", __func__, request->client()->remoteIP().toString().c_str(), request->url().c_str()); - if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 || strcmp(request->url().c_str(), SSIDS_PATH) == 0 || strcmp(request->url().c_str(), INDEX_PATH) == 0 || strcmp(request->url().c_str(), TMP_PATH) == 0 || strcmp(request->url().c_str(), PLAYLIST_SD_PATH) == 0 || strcmp(request->url().c_str(), INDEX_SD_PATH) == 0) { + if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 || + strcmp(request->url().c_str(), SSIDS_PATH) == 0 || + strcmp(request->url().c_str(), INDEX_PATH) == 0 || + strcmp(request->url().c_str(), TMP_PATH) == 0 || + strcmp(request->url().c_str(), PLAYLIST_SD_PATH) == 0 || + strcmp(request->url().c_str(), INDEX_SD_PATH) == 0) { #ifdef MQTT_ROOT_TOPIC if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0) while (mqttplaylistblock) vTaskDelay(5); #endif @@ -792,14 +833,14 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { } if (network.status == CONNECTED) { bool commandFound=false; - if (request->hasArg("start")) { player.sendCommand({PR_PLAY, config.store.lastStation}); commandFound=true; } + if (request->hasArg("start")) { player.sendCommand({PR_PLAY, config.lastStation()}); commandFound=true; } if (request->hasArg("stop")) { player.sendCommand({PR_STOP, 0}); commandFound=true; } if (request->hasArg("toggle")) { player.toggle(); commandFound=true; } if (request->hasArg("prev")) { player.prev(); commandFound=true; } if (request->hasArg("next")) { player.next(); commandFound=true; } if (request->hasArg("volm")) { player.stepVol(false); commandFound=true; } if (request->hasArg("volp")) { player.stepVol(true); commandFound=true; } - + if (request->hasArg("reset")) { config.reset(); commandFound=true; } if (request->hasArg("trebble") && request->hasArg("middle") && request->hasArg("bass")) { AsyncWebParameter* pt = request->getParam("trebble", request->method() == HTTP_POST); AsyncWebParameter* pm = request->getParam("middle", request->method() == HTTP_POST); @@ -825,7 +866,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { int id = atoi(p->value().c_str()); if (id < 1) id = 1; if (id > config.store.countStation) id = config.store.countStation; - config.sdResumePos = 0; + //config.sdResumePos = 0; player.sendCommand({PR_PLAY, id}); commandFound=true; DBGVB("[%s] play=%d", __func__, id); @@ -871,8 +912,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { } if (request->hasArg("clearspiffs")) { if(config.spiffsCleanup()){ - config.store.play_mode = PM_WEB; - config.save(); + config.saveValue(&config.store.play_mode, static_cast(PM_WEB)); request->redirect("/"); ESP.restart(); }else{ diff --git a/yoRadio/src/core/network.cpp b/yoRadio/src/core/network.cpp index a6e6a76..3e6fcf7 100644 --- a/yoRadio/src/core/network.cpp +++ b/yoRadio/src/core/network.cpp @@ -8,7 +8,7 @@ #include "mqtt.h" #ifndef WIFI_ATTEMPTS - #define WIFI_ATTEMPTS 16 + #define WIFI_ATTEMPTS 16 #endif MyNetwork network; @@ -28,8 +28,8 @@ void ticks() { static const uint32_t timeSyncInterval=86400; static uint32_t timeSyncTicks = 0; #else - static const uint16_t timeSyncInterval=3600; - static uint16_t timeSyncTicks = 0; + static const uint16_t timeSyncInterval=3600; + static uint16_t timeSyncTicks = 0; #endif static uint16_t weatherSyncTicks = 0; static bool divrssi; @@ -50,8 +50,8 @@ void ticks() { } } #if RTCSUPPORTED - rtc.getTime(&network.timeinfo); - mktime(&network.timeinfo); + rtc.getTime(&network.timeinfo); + mktime(&network.timeinfo); display.putRequest(CLOCK); #else if(network.timeinfo.tm_year>100 || network.status == SDREADY) { @@ -79,11 +79,11 @@ void MyNetwork::WiFiReconnected(WiFiEvent_t event, WiFiEventInfo_t info){ delay(100); display.putRequest(NEWMODE, PLAYER); if(config.getMode()==PM_SDCARD) { - network.status=CONNECTED; - display.putRequest(NEWIP, 0); + network.status=CONNECTED; + display.putRequest(NEWIP, 0); }else{ - display.putRequest(NEWMODE, PLAYER); - if (network.lostPlaying) player.sendCommand({PR_PLAY, config.store.lastStation}); + display.putRequest(NEWMODE, PLAYER); + if (network.lostPlaying) player.sendCommand({PR_PLAY, config.lastStation()}); } #ifdef MQTT_ROOT_TOPIC connectToMqtt(); @@ -94,12 +94,12 @@ void MyNetwork::WiFiLostConnection(WiFiEvent_t event, WiFiEventInfo_t info){ if(!network.beginReconnect){ Serial.printf("Lost connection, reconnecting to %s...\n", config.ssids[config.store.lastSSID-1].ssid); if(config.getMode()==PM_SDCARD) { - network.status=SDREADY; - display.putRequest(NEWIP, 0); - }else{ - network.lostPlaying = player.isRunning(); - if (network.lostPlaying) { player.lockOutput = true; player.sendCommand({PR_STOP, 0}); } - display.putRequest(NEWMODE, LOST); + network.status=SDREADY; + display.putRequest(NEWIP, 0); + }else{ + network.lostPlaying = player.isRunning(); + if (network.lostPlaying) { player.lockOutput = true; player.sendCommand({PR_STOP, 0}); } + display.putRequest(NEWMODE, LOST); } } network.beginReconnect = true; @@ -143,8 +143,8 @@ bool MyNetwork::wifiBegin(bool silent){ } void searchWiFi(void * pvParameters){ - if(!network.wifiBegin(true)){ - delay(10000); + if(!network.wifiBegin(true)){ + delay(10000); xTaskCreatePinnedToCore(searchWiFi, "searchWiFi", 1024 * 4, NULL, 0, NULL, 0); }else{ network.status = CONNECTED; @@ -153,7 +153,7 @@ void searchWiFi(void * pvParameters){ network.setWifiParams(); display.putRequest(NEWIP, 0); } - vTaskDelete( NULL ); + vTaskDelete( NULL ); } #define DBGAP false @@ -177,16 +177,16 @@ void MyNetwork::begin() { status = CONNECTED; setWifiParams(); }else{ - status = SDREADY; - xTaskCreatePinnedToCore(searchWiFi, "searchWiFi", 1024 * 4, NULL, 0, NULL, 0); + status = SDREADY; + xTaskCreatePinnedToCore(searchWiFi, "searchWiFi", 1024 * 4, NULL, 0, NULL, 0); } Serial.println("##[BOOT]#\tdone"); if(REAL_LEDBUILTIN!=255) digitalWrite(REAL_LEDBUILTIN, LOW); #if RTCSUPPORTED - rtc.getTime(&network.timeinfo); - mktime(&network.timeinfo); + rtc.getTime(&network.timeinfo); + mktime(&network.timeinfo); display.putRequest(CLOCK); #endif ctimer.attach(1, ticks); @@ -258,7 +258,7 @@ void doSync( void * pvParameters ) { display.putRequest(CLOCK); network.requestTimeSync(true); #if RTCSUPPORTED - if (config.isRTCFound()) rtc.setTime(&network.timeinfo); + if (config.isRTCFound()) rtc.setTime(&network.timeinfo); #endif }else{ if(tsFailCnt<4){ diff --git a/yoRadio/src/core/options.h b/yoRadio/src/core/options.h index efa9e8d..4b14cba 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.351" +#define YOVERSION "0.9.368" /******************************************************* DO NOT EDIT THIS FILE. diff --git a/yoRadio/src/core/player.cpp b/yoRadio/src/core/player.cpp index a6dd524..8761ffb 100644 --- a/yoRadio/src/core/player.cpp +++ b/yoRadio/src/core/player.cpp @@ -1,7 +1,5 @@ #include "options.h" - #include "player.h" - #include "config.h" #include "telnet.h" #include "display.h" @@ -93,6 +91,7 @@ void Player::setError(const char *e){ } void Player::_stop(bool alreadyStopped){ + log_i("%s called", __func__); if(config.getMode()==PM_SDCARD && !alreadyStopped) config.sdResumePos = player.getFilePos(); _status = STOPPED; setOutputPins(false); @@ -124,11 +123,13 @@ void Player::initHeaders(const char *file) { #ifndef PL_QUEUE_TICKS #define PL_QUEUE_TICKS 0 #endif - +#ifndef PL_QUEUE_TICKS_ST + #define PL_QUEUE_TICKS_ST 15 +#endif void Player::loop() { if(playerQueue==NULL) return; playerRequestParams_t requestP; - if(xQueueReceive(playerQueue, &requestP, PL_QUEUE_TICKS)){ + if(xQueueReceive(playerQueue, &requestP, isRunning()?PL_QUEUE_TICKS:PL_QUEUE_TICKS_ST)){ switch (requestP.type){ case PR_STOP: _stop(); break; case PR_PLAY: { @@ -147,7 +148,12 @@ void Player::loop() { } #ifdef USE_SD case PR_CHECKSD: { - sdman.checkSD(); + if(config.getMode()==PM_SDCARD){ + if(!sdman.cardPresent()){ + sdman.stop(); + config.changeMode(PM_WEB); + } + } break; } #endif @@ -176,6 +182,7 @@ void Player::setOutputPins(bool isPlaying) { } void Player::_play(uint16_t stationId) { + log_i("%s called, stationId=%d", __func__, stationId); setError(""); remoteStationName = false; config.setDspOn(1); @@ -197,11 +204,10 @@ void Player::_play(uint16_t stationId) { netserver.loop(); config.setSmartStart(0); bool isConnected = false; - if(config.getMode()==PM_SDCARD && SDC_CS!=255) + if(config.getMode()==PM_SDCARD && SDC_CS!=255){ isConnected=connecttoFS(sdman,config.station.url,config.sdResumePos==0?_resumeFilePos:config.sdResumePos-player.sd_min); - else { - config.store.play_mode=PM_WEB; - config.save(); + }else { + config.saveValue(&config.store.play_mode, static_cast(PM_WEB)); } if(config.getMode()==PM_WEB) isConnected=connecttohost(config.station.url); if(isConnected){ @@ -209,7 +215,7 @@ void Player::_play(uint16_t stationId) { _status = PLAYING; if(config.getMode()==PM_SDCARD) { config.sdResumePos = 0; - config.backupSDStation = stationId; + config.saveValue(&config.store.lastSdStation, stationId); } //config.setTitle(""); config.setSmartStart(1); @@ -253,26 +259,29 @@ void Player::browseUrl(){ #endif void Player::prev() { - if(config.getMode()==PM_WEB || !config.sdSnuffle){ - if (config.store.lastStation == 1) config.store.lastStation = config.store.countStation; else config.store.lastStation--; + + uint16_t lastStation = config.lastStation(); + if(config.getMode()==PM_WEB || !config.store.sdsnuffle){ + if (lastStation == 1) config.lastStation(config.store.countStation); else config.lastStation(lastStation-1); } - sendCommand({PR_PLAY, config.store.lastStation}); + sendCommand({PR_PLAY, config.lastStation()}); } void Player::next() { - if(config.getMode()==PM_WEB || !config.sdSnuffle){ - if (config.store.lastStation == config.store.countStation) config.store.lastStation = 1; else config.store.lastStation++; + uint16_t lastStation = config.lastStation(); + if(config.getMode()==PM_WEB || !config.store.sdsnuffle){ + if (lastStation == config.store.countStation) config.lastStation(1); else config.lastStation(lastStation+1); }else{ - config.store.lastStation = random(1, config.store.countStation); + config.lastStation(random(1, config.store.countStation)); } - sendCommand({PR_PLAY, config.store.lastStation}); + sendCommand({PR_PLAY, config.lastStation()}); } void Player::toggle() { if (_status == PLAYING) { sendCommand({PR_STOP, 0}); } else { - sendCommand({PR_PLAY, config.store.lastStation}); + sendCommand({PR_PLAY, config.lastStation()}); } } diff --git a/yoRadio/src/core/sdmanager.cpp b/yoRadio/src/core/sdmanager.cpp index c1733ce..85fbf69 100644 --- a/yoRadio/src/core/sdmanager.cpp +++ b/yoRadio/src/core/sdmanager.cpp @@ -6,67 +6,43 @@ #if defined(SD_SPIPINS) || SD_HSPI SPIClass SDSPI(HSPI); +#define SDREALSPI SDSPI +#else + #define SDREALSPI SPI +#endif + +#ifndef SDSPISPEED + #define SDSPISPEED 4000000 #endif SDManager sdman(FSImplPtr(new VFSImpl())); -bool SDManager::init(){ - ready = false; - #if defined(SD_SPIPINS) || SD_HSPI - ready = begin(SDC_CS, SDSPI); - #else - ready = begin(SDC_CS); - #endif +bool SDManager::start(){ + ready = begin(SDC_CS, SDREALSPI, SDSPISPEED); + vTaskDelay(10); + if(!ready) ready = begin(SDC_CS, SDREALSPI, SDSPISPEED); + vTaskDelay(10); + if(!ready) ready = begin(SDC_CS, SDREALSPI, SDSPISPEED); return ready; } +void SDManager::stop(){ + end(); + ready = false; +} +#include "diskio_impl.h" bool SDManager::cardPresent() { + + if(!ready) return false; if(sectorSize()<1) { - return false; + return false; } uint8_t buff[sectorSize()] = { 0 }; bool bread = readRAW(buff, 1); - if(sectorSize()>0 && !bread) end(); + if(sectorSize()>0 && !bread) return false; return bread; } -void SDManager::mount(){ - if(display.mode()==SDCHANGE) return; - uint16_t ssz = sectorSize(); - if(ssz<1) init(); - if(!cardPresent()) { - if(config.getMode()==PM_SDCARD){ - ready = false; - } - }else{ - if(!ready){ - if(!init()){ - Serial.println("##[ERROR]#\tCard Mount Failed"); - }else{ - ready = true; - } - } - } -} - -void SDManager::checkSD(){ - cardStatus_e prevCardStatus = _cardStatus; - if(cardPresent()){ - if(_cardStatus==CS_NONE || _cardStatus==CS_PRESENT || _cardStatus==CS_EJECTED) { - _cardStatus=CS_PRESENT; - }else{ - _cardStatus=CS_MOUNTED; - } - if(_cardStatus==CS_PRESENT && config.getMode()==PM_WEB && SD_AUTOPLAY && prevCardStatus==CS_EJECTED) config.changeMode(PM_SDCARD); - }else{ - if(_cardStatus==CS_MOUNTED || _cardStatus==CS_PRESENT || _cardStatus==CS_EJECTED){ - if(_cardStatus!=CS_EJECTED && config.getMode()==PM_SDCARD && SD_AUTOPLAY) config.changeMode(PM_WEB); - _cardStatus=CS_EJECTED; - } - config.backupSDStation = 0; - } -} - bool SDManager::_checkNoMedia(const char* path){ char nomedia[BUFLEN]= {0}; strlcat(nomedia, path, BUFLEN); diff --git a/yoRadio/src/core/sdmanager.h b/yoRadio/src/core/sdmanager.h index 63d9135..413c703 100644 --- a/yoRadio/src/core/sdmanager.h +++ b/yoRadio/src/core/sdmanager.h @@ -7,26 +7,18 @@ #include "sd_diskio.h" #include "options.h" -enum cardStatus_e : uint8_t { CS_NONE=0, CS_PRESENT=1, CS_MOUNTED=2, CS_EJECTED=3 }; - class SDManager : public SDFS { public: bool ready; public: SDManager(FSImplPtr impl) : SDFS(impl) {} - - bool init(); - void mount(); + bool start(); + void stop(); bool cardPresent(); void listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels); void indexSDPlaylist(); - void checkSD(); - cardStatus_e status(){ return _cardStatus; }; - void status(cardStatus_e newstatus){ _cardStatus=newstatus; }; - void clearCardStatus() { if(_cardStatus!=CS_NONE) _cardStatus=CS_NONE; } private: uint32_t _sdFCount; - cardStatus_e _cardStatus; private: bool _checkNoMedia(const char* path); bool _endsWith (const char* base, const char* str); diff --git a/yoRadio/src/core/telnet.cpp b/yoRadio/src/core/telnet.cpp index 4e4296d..fae20b9 100644 --- a/yoRadio/src/core/telnet.cpp +++ b/yoRadio/src/core/telnet.cpp @@ -13,22 +13,22 @@ bool Telnet::_isIPSet(IPAddress ip) { } bool Telnet::begin(bool quiet) { - if(network.status==SDREADY) { - BOOTLOG("Ready in SD Mode!"); + if(network.status==SDREADY) { + BOOTLOG("Ready in SD Mode!"); BOOTLOG("------------------------------------------------"); Serial.println("##[BOOT]#"); - return true; - } + return true; + } if(!quiet) Serial.print("##[BOOT]#\ttelnet.begin\t"); if (WiFi.status() == WL_CONNECTED || _isIPSet(WiFi.softAPIP())) { server.begin(); server.setNoDelay(true); if(!quiet){ - Serial.println("done"); - Serial.println("##[BOOT]#"); - BOOTLOG("Ready! Go to http:/%s/ to configure", WiFi.localIP().toString().c_str()); - BOOTLOG("------------------------------------------------"); - Serial.println("##[BOOT]#"); + Serial.println("done"); + Serial.println("##[BOOT]#"); + BOOTLOG("Ready! Go to http:/%s/ to configure", WiFi.localIP().toString().c_str()); + BOOTLOG("------------------------------------------------"); + Serial.println("##[BOOT]#"); } return true; } else { @@ -68,9 +68,9 @@ void Telnet::handleSerial(){ void Telnet::loop() { if(network.status==SDREADY || network.status!=CONNECTED) { - handleSerial(); - return; - } + handleSerial(); + return; + } uint8_t i; if (WiFi.status() == WL_CONNECTED) { if (server.hasClient()) { @@ -168,7 +168,7 @@ void Telnet::info() { char timeStringBuff[50]; strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &network.timeinfo); telnet.printf("##SYS.DATE#: %s\n", timeStringBuff); //TODO timezone offset - telnet.printf("##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name); + telnet.printf("##CLI.NAMESET#: %d %s\n", config.lastStation(), config.station.name); if (player.status() == PLAYING) { telnet.printf("##CLI.META#: %s\n", config.station.title); } @@ -202,7 +202,7 @@ void Telnet::on_input(const char* str, uint8_t clientId) { return; } if (strcmp(str, "cli.start") == 0 || strcmp(str, "start") == 0 || strcmp(str, "cli.play") == 0 || strcmp(str, "play") == 0) { - player.sendCommand({PR_PLAY, config.store.lastStation}); + player.sendCommand({PR_PLAY, config.lastStation()}); return; } if (strcmp(str, "cli.vol") == 0 || strcmp(str, "vol") == 0) { @@ -234,9 +234,8 @@ void Telnet::on_input(const char* str, uint8_t clientId) { } int ainfo; if (sscanf(str, "audioinfo(%d)", &ainfo) == 1 || sscanf(str, "cli.audioinfo(\"%d\")", &ainfo) == 1 || sscanf(str, "audioinfo %d", &ainfo) == 1) { - config.store.audioinfo = ainfo > 0; + config.saveValue(&config.store.audioinfo, ainfo > 0); printf(clientId, "new audioinfo value is: %d\n> ", config.store.audioinfo); - config.save(); return; } if (strcmp(str, "cli.smartstart") == 0 || strcmp(str, "smartstart") == 0) { @@ -245,9 +244,8 @@ void Telnet::on_input(const char* str, uint8_t clientId) { } int sstart; if (sscanf(str, "smartstart(%d)", &sstart) == 1 || sscanf(str, "cli.smartstart(\"%d\")", &sstart) == 1 || sscanf(str, "smartstart %d", &sstart) == 1) { - config.store.smartstart = (uint8_t)sstart; + config.saveValue(&config.store.smartstart, static_cast(sstart)); printf(clientId, "new smartstart value is: %d\n> ", config.store.smartstart); - config.save(); return; } if (strcmp(str, "cli.list") == 0 || strcmp(str, "list") == 0) { @@ -278,7 +276,7 @@ void Telnet::on_input(const char* str, uint8_t clientId) { } else { printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin); } - printf(clientId, "##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name); + printf(clientId, "##CLI.NAMESET#: %d %s\n", config.lastStation(), config.station.name); if (player.status() == PLAYING) { printf(clientId, "##CLI.META#: %s\n", config.station.title); } @@ -368,6 +366,10 @@ void Telnet::on_input(const char* str, uint8_t clientId) { ESP.restart(); return; } + if (strcmp(str, "sys.reset") == 0 || strcmp(str, "reset") == 0) { + config.reset(); + return; + } if (strcmp(str, "wifi.list") == 0 || strcmp(str, "wifi") == 0) { printf(clientId, "#WIFI.SCAN#\n"); int n = WiFi.scanNetworks(); diff --git a/yoRadio/src/displays/nextion.cpp b/yoRadio/src/displays/nextion.cpp index 89558e7..adab5d0 100644 --- a/yoRadio/src/displays/nextion.cpp +++ b/yoRadio/src/displays/nextion.cpp @@ -55,8 +55,8 @@ void Nextion::begin(bool dummy) { } void Nextion::start(){ - Serial.print("##[BOOT]#\tNextion.start\t"); - delay(100); + Serial.print("##[BOOT]#\tNextion.start\t"); + delay(100); if (network.status != CONNECTED) { apScreen(); return; @@ -271,12 +271,10 @@ void Nextion::loop() { network.forceTimeSync = true; } if (sscanf(rxbuf, "audioinfo=%d", &scanDigit) == 1){ - config.store.audioinfo = scanDigit; - config.save(); + config.saveValue(&config.store.audioinfo, static_cast(scanDigit)); } if (sscanf(rxbuf, "smartstart=%d", &scanDigit) == 1){ - config.store.smartstart = scanDigit==0?2:1; - config.save(); + config.saveValue(&config.store.smartstart, static_cast(scanDigit==0?2:1)); } if (sscanf(rxbuf, "addssid=%s", scanBuf) == 1){ wifisettings+=(String(scanBuf)+"\t"); @@ -433,18 +431,18 @@ void Nextion::localTime(struct tm timeinfo){ } void Nextion::printPLitem(uint8_t pos, const char* item){ - char cmd[60]={0}; - snprintf(cmd, sizeof(cmd) - 1, "t%d.txt=\"%s\"", pos, nextion.utf8Rus((char*)item, true)); + char cmd[60]={0}; + snprintf(cmd, sizeof(cmd) - 1, "t%d.txt=\"%s\"", pos, nextion.utf8Rus((char*)item, true)); putcmd(cmd); } void Nextion::drawPlaylist(uint16_t currentPlItem){ - mode=STATIONS; + mode=STATIONS; uint8_t lastPos = config.fillPlMenu(currentPlItem - 3, 7, true); if(lastPos<7){ - for(int i=0;i<7-lastPos;i++){ - nextion.printPLitem(lastPos+i, ""); - } + for(int i=0;i<7-lastPos;i++){ + nextion.printPLitem(lastPos+i, ""); + } } _volDelay = millis(); } @@ -460,7 +458,7 @@ void Nextion::swichMode(displayMode_e newmode){ _volDelay = millis(); } if (newmode == mode) { - return; + return; } mode = newmode; #ifdef DUMMYDISPLAY @@ -489,9 +487,9 @@ void Nextion::swichMode(displayMode_e newmode){ if (newmode == STATIONS) { putcmd("page playlist"); #ifdef DUMMYDISPLAY - display.currentPlItem = config.store.lastStation; + display.currentPlItem = config.lastStation(); #endif - drawPlaylist(config.store.lastStation); + drawPlaylist(config.lastStation()); } } diff --git a/yoRadio/src/main.cpp b/yoRadio/src/main.cpp new file mode 100644 index 0000000..22e3531 --- /dev/null +++ b/yoRadio/src/main.cpp @@ -0,0 +1,60 @@ +#include "Arduino.h" +#include "core/options.h" +#include "core/config.h" +#include "core/telnet.h" +#include "core/player.h" +#include "core/display.h" +#include "core/network.h" +#include "core/netserver.h" +#include "core/controls.h" +#include "core/mqtt.h" +#include "core/optionschecker.h" + +extern __attribute__((weak)) void yoradio_on_setup(); + +void setup() { + Serial.begin(115200); + if(REAL_LEDBUILTIN!=255) pinMode(REAL_LEDBUILTIN, OUTPUT); + if (yoradio_on_setup) yoradio_on_setup(); + pm.on_setup(); + config.init(); + display.init(); + player.init(); + network.begin(); + if (network.status != CONNECTED && network.status!=SDREADY) { + netserver.begin(); + initControls(); + display.putRequest(DSP_START); + while(!display.ready()) delay(10); + return; + } + if(SDC_CS!=255) { + display.putRequest(WAITFORSD, 0); + Serial.print("##[BOOT]#\tSD search\t"); + } + config.initPlaylistMode(); + netserver.begin(); + telnet.begin(); + initControls(); + display.putRequest(DSP_START); + while(!display.ready()) delay(10); + #ifdef MQTT_ROOT_TOPIC + mqttInit(); + #endif + if (config.getMode()==PM_SDCARD) player.initHeaders(config.station.url); + player.lockOutput=false; + if (config.store.smartstart == 1) player.sendCommand({PR_PLAY, config.lastStation()}); + pm.on_end_setup(); +} + +void loop() { + telnet.loop(); + if (network.status == CONNECTED || network.status==SDREADY) { + player.loop(); + //loopControls(); + } + loopControls(); + netserver.loop(); +} + +#include "core/audiohandlers.h" diff --git a/yoRadio/yoRadio.ino b/yoRadio/yoRadio.ino index f77ad36..9c0fe9b 100644 --- a/yoRadio/yoRadio.ino +++ b/yoRadio/yoRadio.ino @@ -15,63 +15,49 @@ * Here goes! * ============================================================================================================ */ -#include "Arduino.h" -#include "src/core/options.h" -#include "src/core/config.h" -#include "src/core/telnet.h" -#include "src/core/player.h" -#include "src/core/display.h" -#include "src/core/network.h" -#include "src/core/netserver.h" -#include "src/core/controls.h" -#include "src/core/mqtt.h" -#include "src/core/optionschecker.h" - -extern __attribute__((weak)) void yoradio_on_setup(); - -void setup() { - Serial.begin(115200); - if(REAL_LEDBUILTIN!=255) pinMode(REAL_LEDBUILTIN, OUTPUT); - if (yoradio_on_setup) yoradio_on_setup(); - pm.on_setup(); - config.init(); - display.init(); - player.init(); - network.begin(); - if (network.status != CONNECTED && network.status!=SDREADY) { - netserver.begin(); - initControls(); - display.putRequest(DSP_START); - while(!display.ready()) delay(10); - return; - } - if(SDC_CS!=255) { - display.putRequest(WAITFORSD, 0); - Serial.print("##[BOOT]#\tSD search\t"); - } - config.initPlaylistMode(); - netserver.begin(); - telnet.begin(); - initControls(); - display.putRequest(DSP_START); - while(!display.ready()) delay(10); - #ifdef MQTT_ROOT_TOPIC - mqttInit(); - #endif - if (config.getMode()==PM_SDCARD) player.initHeaders(config.station.url); - player.lockOutput=false; - if (config.store.smartstart == 1) player.sendCommand({PR_PLAY, config.store.lastStation}); - pm.on_end_setup(); -} - -void loop() { - telnet.loop(); - if (network.status == CONNECTED || network.status==SDREADY) { - player.loop(); - //loopControls(); - } - loopControls(); - netserver.loop(); -} - -#include "src/core/audiohandlers.h" + +/* + * + * ============================================================================================================ + * + * + * ---------- ---------- + * ------------ ------------ + * -------------- -------------- + * -------------- --------------- + * -------------- -------------- + * ------------ ------------- + * -------- -------- + * + * + * # ------- + * ####### ------------------- + * ##### #####------------------------ + * ############ ### --*#=------------------------ %### ## + * ### ### ## ### ----+#*-------------------------- ### #### ### + * ### ### ### ### -----+#*--------------------------- ### %### ### ## ## + * ## ## ### ### ------*#*---------------------------= #### #### #### ## ## + * ## ## ### ### ------+#*=----- -------=--=#*-- #### #### ##### #### + * ## ## ### ### ------+#+------ -=+*=--=+#*---*#### #### ###### ### + * ## ## ### ### -----=#*------- ### %##=----*#*---=*### #### ## ## ### + * # # ### ######+-==+=------=*####### #####----*#*---+=*## ##### ## ### + * ## ### #### ----------+*=---***----=##+-----*#*=-==-=## ### %#### + * ## ### ### --------+#+----=#*=---++#*----=+*#=-+---=#### + * ## #### #### ------=##=----=##=--==-**=---+=*#===------- + * ## ### #### -----+##=----+##---+---+*--+=-+#*---------- + * ##### ### -----+#+----+=#+-==----------+#+---------- + * ### -----+#=--==--### #### + * ### ------***------ ## ### + * ### --------------- ### ## + * ### ### -------------------### ## ----- + * #### ### -----------------++---=*------------- + * ######### ---------------*=---=+-------------- + * ------------=*---+=--------------- + * -----------++==----------------- + * --------------------------- + * -------------------- + * + * + * ============================================================================================================ + * + */