diff --git a/README.md b/README.md index f9f703b..b743641 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,24 @@ Work is in progress... --- ## Version history +#### v0.7.490 +**!!! a [full update](#update-over-web-interface) with Sketch data upload is required. After updating please press CTRL+F5 in browser !!!** \ +**Please backup playlist.csv and wifi.csv before updating.** +- fixed playlist break down when saving it +- fixed bug with cropped song titles on single line displays (GC9106, ST7735mini, N5110 etc.) +- netserver - optimization and refactoring +- web interface optimization +- the AUDIOBUFFER_MULTIPLIER parameter is deprecated. New parameter AUDIOBUFFER_MULTIPLIER2. If everything works fine, then it is better not to touch it. +- new setting VS_PATCH_ENABLE (see PS) +- fixing other bugs + +_**PS:** A bug was found with the lack of sound on some (not all) green VS1053 boards. +If there is no sound, you need to assign in myoptions_ +``` +#define VS_PATCH_ENABLE false +``` +_On red boards and normally working green boards, nothing else needs to be done._ + #### v0.7.414 - fixed non latin long titles of songs error diff --git a/yoRadio/audiohandlers.ino b/yoRadio/audiohandlers.ino index 18139c4..74bff8e 100644 --- a/yoRadio/audiohandlers.ino +++ b/yoRadio/audiohandlers.ino @@ -15,7 +15,7 @@ void audio_info(const char *info) { player.mode = STOPPED; player.stopInfo(); } - if (strstr(info, "not supported") != NULL){ + if (strstr(info, "not supported") != NULL || strstr(info, "Account already in use") != NULL){ config.setTitle(info); netserver.requestOnChange(TITLE, 0); player.setOutputPins(false); @@ -47,20 +47,32 @@ bool printable(const char *info) { } void audio_showstation(const char *info) { + DBGVB("[%s] info = %s", __func__, info); if (strlen(info) > 0) { bool p = printable(info); - config.setTitle(p?info:"*****"); + config.setTitle(p?info:config.station.name); netserver.requestOnChange(TITLE, 0); } } void audio_showstreamtitle(const char *info) { + DBGVB("[%s] info = %s", __func__, info); + if (strstr(info, "Account already in use") != NULL){ + config.setTitle(info); + netserver.requestOnChange(TITLE, 0); + player.setOutputPins(false); + player.setDefaults(); + if (player_on_stop_play) player_on_stop_play(); + player.mode = STOPPED; + player.stopInfo(); + return; + } if (strlen(info) > 0) { bool p = printable(info); #ifdef DEBUG_TITLES config.setTitle(DEBUG_TITLES); #else - config.setTitle(p?info:"*****"); + config.setTitle(p?info:config.station.name); #endif netserver.requestOnChange(TITLE, 0); } diff --git a/yoRadio/config.cpp b/yoRadio/config.cpp index ea8ace8..74c8d60 100644 --- a/yoRadio/config.cpp +++ b/yoRadio/config.cpp @@ -443,7 +443,7 @@ bool Config::parseSsid(const char* line, char* ssid, char* pass) { return true; } -bool Config::saveWifi(const char* post) { +bool Config::saveWifiFromNextion(const char* post){ File file = SPIFFS.open(SSIDS_PATH, "w"); if (!file) { return false; @@ -455,6 +455,14 @@ bool Config::saveWifi(const char* post) { } } +bool Config::saveWifi() { + if (!SPIFFS.exists(TMP_PATH)) return false; + SPIFFS.remove(SSIDS_PATH); + SPIFFS.rename(TMP_PATH, SSIDS_PATH); + ESP.restart(); + return true; +} + bool Config::initNetwork() { File file = SPIFFS.open(SSIDS_PATH, "r"); if (!file || file.isDirectory()) { diff --git a/yoRadio/config.h b/yoRadio/config.h index 4c3e599..b046946 100644 --- a/yoRadio/config.h +++ b/yoRadio/config.h @@ -147,7 +147,8 @@ class Config { bool parseSsid(const char* line, char* ssid, char* pass); void loadStation(uint16_t station); bool initNetwork(); - bool saveWifi(const char* post); + bool saveWifi(); + bool saveWifiFromNextion(const char* post); void setSmartStart(byte ss); void initPlaylist(); void indexPlaylist(); diff --git a/yoRadio/data/www/script.js.gz b/yoRadio/data/www/script.js.gz index ba3ea9f..aa35f08 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/settings.html b/yoRadio/data/www/settings.html index cbc32e1..2a381f3 100644 --- a/yoRadio/data/www/settings.html +++ b/yoRadio/data/www/settings.html @@ -177,6 +177,7 @@
+
Save & Reboot
diff --git a/yoRadio/display.cpp b/yoRadio/display.cpp index ef16f8b..5b0f940 100644 --- a/yoRadio/display.cpp +++ b/yoRadio/display.cpp @@ -580,7 +580,7 @@ char *split(char *str, const char *delim) { } void Display::title() { - DBGVB("call of %s(), config.station.title=%s", __func__, config.station.title); + DBGVB("[%s] config.station.title = %s", __func__, config.station.title); if (strlen(config.station.title) > 0) { char tmpbuf[strlen(config.station.title)+1]; strlcpy(tmpbuf, config.station.title, strlen(config.station.title)+1); @@ -589,7 +589,7 @@ void Display::title() { title1.setText(dsp.utf8Rus(tmpbuf, true)); title2.setText(dsp.utf8Rus(stitle, true)); }else{ - title1.setText(dsp.utf8Rus(tmpbuf, true)); + title1.setText(dsp.utf8Rus(config.station.title, true)); title2.setText(dsp.utf8Rus("", true)); } #ifdef USE_NEXTION diff --git a/yoRadio/netserver.cpp b/yoRadio/netserver.cpp index 9520921..8b38b18 100644 --- a/yoRadio/netserver.cpp +++ b/yoRadio/netserver.cpp @@ -25,123 +25,41 @@ AsyncUDP udp; String processor(const String& var); void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); +void handleUpdate(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); +void handleHTTPArgs(AsyncWebServerRequest * request); void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len); -void handleHTTPPost(AsyncWebServerRequest * request); bool shouldReboot = false; +#ifdef MQTT_HOST +Ticker mqttplaylistticker; +bool mqttplaylistblock = false; +void mqttplaylistSend() { + mqttplaylistblock = true; + mqttplaylistticker.detach(); + mqttPublishPlaylist(); + mqttplaylistblock = false; +} +#endif -char* updateError(){ +char* updateError() { static char ret[140] = {0}; sprintf(ret, "Update failed with error (%d)
%s", (int)Update.getError(), Update.errorString()); return ret; } -void NetServer::takeMallocDog(){ - int mcb = heap_caps_get_free_size(MALLOC_CAP_8BIT); - int mci = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); - (void)mci; - DBGVB("MALLOC_CAP_8BIT=%d, MALLOC_CAP_INTERNAL=%d", mcb, mci); - resumePlay = mcb < MIN_MALLOC; - if (resumePlay) { - player.toggle(); - vTaskDelay(150); - xSemaphoreTake(player.playmutex, portMAX_DELAY); - } -} - -void NetServer::giveMallocDog(){ - if (resumePlay) { - resumePlay = false; - vTaskDelay(150); - xSemaphoreGive(player.playmutex); - player.toggle(); - } -} - bool NetServer::begin() { - importRequest = false; + importRequest = IMDONE; irRecordEnable = false; - webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { - if (network.status == CONNECTED) { - netserver.htmlPath = PINDEX; - netserver.chunkedHtmlPage(String(), request); - }else{ - netserver.htmlPath = PSETTINGS; - netserver.chunkedHtmlPage(String(), request); - } - }); - + webserver.on("/", HTTP_ANY, handleHTTPArgs); + webserver.on(PLAYLIST_PATH, HTTP_GET, handleHTTPArgs); + webserver.on(INDEX_PATH, HTTP_GET, handleHTTPArgs); + webserver.on(SSIDS_PATH, HTTP_GET, handleHTTPArgs); + webserver.on("/upload", HTTP_POST, beginUpload, handleUpload); + webserver.on("/update", HTTP_GET, handleHTTPArgs); + webserver.on("/update", HTTP_POST, beginUpdate, handleUpdate); + webserver.on("/settings", HTTP_GET, handleHTTPArgs); + if (IR_PIN != 255) webserver.on("/ir", HTTP_GET, handleHTTPArgs); webserver.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=31536000"); - - webserver.on("/", HTTP_POST, [](AsyncWebServerRequest * request) { - handleHTTPPost(request); - }); - webserver.on(PLAYLIST_PATH, HTTP_GET, [](AsyncWebServerRequest * request) { - netserver.takeMallocDog(); - request->send(SPIFFS, PLAYLIST_PATH, "application/octet-stream"); - netserver.giveMallocDog(); - DBGVB("PLAYLIST_PATH client ip=%s", request->client()->remoteIP().toString().c_str()); - /*netserver.htmlPath = PPLAYLIST; // TODO - netserver.chunkedHtmlPage("application/octet-stream", request); - netserver.giveMallocDog();*/ - }); - webserver.on(INDEX_PATH, HTTP_GET, [](AsyncWebServerRequest * request) { - request->send(SPIFFS, INDEX_PATH, "application/octet-stream"); - }); - webserver.on(SSIDS_PATH, HTTP_GET, [](AsyncWebServerRequest * request) { - netserver.htmlPath = PSSIDS; - netserver.chunkedHtmlPage("application/octet-stream", request); - }); - webserver.on("/upload", HTTP_POST, [](AsyncWebServerRequest * request) { - //request->send(200); - - }, handleUpload); - webserver.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){ - netserver.htmlPath = PUPDATE; - netserver.chunkedHtmlPage(String(), request); - }); - webserver.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){ - netserver.htmlPath = PSETTINGS; - netserver.chunkedHtmlPage(String(), request); - }); - -#if IR_PIN!=255 - webserver.on("/ir", HTTP_GET, [](AsyncWebServerRequest *request){ - netserver.htmlPath = PIR; - netserver.chunkedHtmlPage(String(), request); - }); -#endif - webserver.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){ - shouldReboot = !Update.hasError(); - AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot?"OK": updateError()); - response->addHeader("Connection", "close"); - request->send(response); - },[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ - if(!index){ - int target = (request->getParam("updatetarget", true)->value() == "spiffs") ? U_SPIFFS : U_FLASH; - Serial.printf("Update Start: %s\n", filename.c_str()); - player.mode = STOPPED; - display.putRequest({NEWMODE, UPDATING}); - if(!Update.begin(UPDATE_SIZE_UNKNOWN, target)){ - Update.printError(Serial); - request->send(200, "text/html", updateError()); - } - } - if(!Update.hasError()){ - if(Update.write(data, len) != len){ - Update.printError(Serial); - request->send(200, "text/html", updateError()); - } - } - if(final){ - if(Update.end(true)){ - Serial.printf("Update Success: %uB\n", index+len); - } else { - Update.printError(Serial); - request->send(200, "text/html", updateError()); - } - } - }); #ifdef CORS_DEBUG DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Origin"), F("*")); DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), F("content-type")); @@ -160,504 +78,439 @@ bool NetServer::begin() { return true; } -void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request){ - max = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 32; - htmlpos = 0; - theend = false; - DBGVB("chunkedHtmlPage client ip=%s", request->client()->remoteIP().toString().c_str()); - AsyncWebServerResponse *response = request->beginChunkedResponse(contentType, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - if(netserver.theend) return 0; - File htmlpage; - switch(netserver.htmlPath){ - case PINDEX: { - htmlpage = SPIFFS.open("/www/index.html", "r"); - break; - } - case PSETTINGS: { - htmlpage = SPIFFS.open("/www/settings.html", "r"); - break; - } - case PUPDATE: { - htmlpage = SPIFFS.open("/www/update.html", "r"); - break; - } - case PIR: { - htmlpage = SPIFFS.open("/www/ir.html", "r"); - break; - } - case PPLAYLIST: { - htmlpage = SPIFFS.open(PLAYLIST_PATH, "r"); - DBGVB("SPIFFS.open(PLAYLIST_PATH)"); - break; - } - case PSSIDS: { - htmlpage = SPIFFS.open(SSIDS_PATH, "r"); - break; - } - default: { - return 0; - break; - } - } - if(!htmlpage) return 0; - uint32_t htmlpagesize = htmlpage.size(); - uint32_t len = htmlpagesize - netserver.htmlpos; - if (len > maxLen) len = maxLen; - if (len > netserver.max) len = netserver.max; - if (len + netserver.htmlpos > htmlpagesize) { - netserver.theend = true; - len = htmlpagesize - netserver.htmlpos; - } - if (len > 0) { - DBGVB("seek to %d in %s and read %d bytes", netserver.htmlpos, htmlpage.name(), len); - htmlpage.seek(netserver.htmlpos, SeekSet); - htmlpage.read(buffer, len); - netserver.htmlpos = netserver.htmlpos + len; - } - if(htmlpage) htmlpage.close(); - return len; - }, processor); // AsyncWebServerResponse +void NetServer::beginUpdate(AsyncWebServerRequest *request) { + shouldReboot = !Update.hasError(); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot ? "OK" : updateError()); + response->addHeader("Connection", "close"); request->send(response); } +void handleUpdate(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { + if (!index) { + int target = (request->getParam("updatetarget", true)->value() == "spiffs") ? U_SPIFFS : U_FLASH; + Serial.printf("Update Start: %s\n", filename.c_str()); + player.mode = STOPPED; + display.putRequest({NEWMODE, UPDATING}); + if (!Update.begin(UPDATE_SIZE_UNKNOWN, target)) { + Update.printError(Serial); + request->send(200, "text/html", updateError()); + } + } + if (!Update.hasError()) { + if (Update.write(data, len) != len) { + Update.printError(Serial); + request->send(200, "text/html", updateError()); + } + } + if (final) { + if (Update.end(true)) { + Serial.printf("Update Success: %uB\n", index + len); + } else { + Update.printError(Serial); + request->send(200, "text/html", updateError()); + } + } +} + +void NetServer::beginUpload(AsyncWebServerRequest *request) { + if (request->hasParam("plfile", true, true)) { + netserver.importRequest = IMPL; + request->send(200); + } else if (request->hasParam("wifile", true, true)) { + netserver.importRequest = IMWIFI; + request->send(200); + } else { + request->send(404); + } +} + +size_t NetServer::chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t index){ + File requiredfile = SPIFFS.open(netserver.chunkedPathBuffer, "r"); + if (!requiredfile) return 0; + size_t filesize = requiredfile.size(); + size_t needread = filesize - index; + if (!needread) 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); + requiredfile.seek(index, SeekSet); + requiredfile.read(buffer, canread); + index += canread; + if (requiredfile) requiredfile.close(); + return canread; +} + +void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request, const char * path, bool gzip) { + memset(chunkedPathBuffer, 0, sizeof(chunkedPathBuffer)); + strlcpy(chunkedPathBuffer, path, sizeof(chunkedPathBuffer)-1); + PLOW(); + AsyncWebServerResponse *response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback, processor); + xSemaphoreTake(player.playmutex, portMAX_DELAY); + request->send(response); + xSemaphoreGive(player.playmutex); PHIG(); +} +/* +void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request, const char * path, bool gzip) { + static char pathbuffer[40] = { 0 }; + strlcpy(pathbuffer, path, 39); + PLOW(); + AsyncWebServerResponse *response = request->beginChunkedResponse(contentType, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { + File requiredfile = SPIFFS.open(pathbuffer, "r"); + if (!requiredfile) return 0; + size_t filesize = requiredfile.size(); + size_t needread = filesize - index; + if (!needread) 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, pathbuffer, canread, maxLen); + requiredfile.seek(index, SeekSet); + requiredfile.read(buffer, canread); + index += canread; + if (requiredfile) requiredfile.close(); + return canread; + }, processor); // AsyncWebServerResponse + + xSemaphoreTake(player.playmutex, portMAX_DELAY); + request->send(response); + xSemaphoreGive(player.playmutex); + PHIG(); +} + */ void NetServer::loop() { - if(shouldReboot){ + if (shouldReboot) { Serial.println("Rebooting..."); delay(100); ESP.restart(); } websocket.cleanupClients(); - if (playlistrequest > 0) { - requestOnChange(PLAYLIST, playlistrequest); - playlistrequest = 0; - } - if (importRequest) { - if (importPlaylist()) { - requestOnChange(PLAYLIST, 0); - } - importRequest = false; - } - if (rssi < 255) { - requestOnChange(NRSSI, 0); + //if (playlistrequest > 0) { requestOnChange(PLAYLIST, playlistrequest); playlistrequest = 0; } /* Cleanup this */ + switch (importRequest) { + case IMPL: importPlaylist(); importRequest = IMDONE; break; + case IMWIFI: config.saveWifi(); importRequest = IMDONE; break; + default: break; } + if (rssi < 255) requestOnChange(NRSSI, 0); } + #if IR_PIN!=255 void NetServer::irToWs(const char* protocol, uint64_t irvalue) { char buf[BUFLEN] = { 0 }; sprintf (buf, "{\"ircode\": %llu, \"protocol\": \"%s\"}", irvalue, protocol); websocket.textAll(buf); } -void NetServer::irValsToWs(){ - if(!irRecordEnable) return; +void NetServer::irValsToWs() { + if (!irRecordEnable) return; char buf[BUFLEN] = { 0 }; sprintf (buf, "{\"irvals\": [%llu, %llu, %llu]}", config.ircodes.irVals[config.irindex][0], config.ircodes.irVals[config.irindex][1], config.ircodes.irVals[config.irindex][2]); websocket.textAll(buf); } #endif + void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t clientId) { AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; char cmd[65], val[65]; if (config.parseWsCommand((const char*)data, cmd, val, 65)) { - if (strcmp(cmd, "getmode") == 0) { - requestOnChange(GETMODE,clientId); - return; - } - if (strcmp(cmd, "getindex") == 0) { - requestOnChange(GETINDEX,clientId); - return; - } - if (strcmp(cmd, "getsystem") == 0) { - requestOnChange(GETSYSTEM,clientId); - return; - } - if (strcmp(cmd, "getscreen") == 0) { - requestOnChange(GETSCREEN,clientId); - return; - } - if (strcmp(cmd, "gettimezone") == 0) { - requestOnChange(GETTIMEZONE,clientId); - return; - } - if (strcmp(cmd, "getcontrols") == 0) { - requestOnChange(GETCONTROLS,clientId); - return; - } - if (strcmp(cmd, "getweather") == 0) { - requestOnChange(GETWEATHER,clientId); - return; - } - if (strcmp(cmd, "getactive") == 0) { - requestOnChange(GETACTIVE,clientId); - return; - } - + if (strcmp(cmd, "getmode") == 0 ) { requestOnChange(GETMODE, clientId); return; } + if (strcmp(cmd, "getindex") == 0 ) { requestOnChange(GETINDEX, clientId); return; } + if (strcmp(cmd, "getsystem") == 0 ) { requestOnChange(GETSYSTEM, clientId); return; } + if (strcmp(cmd, "getscreen") == 0 ) { requestOnChange(GETSCREEN, clientId); return; } + if (strcmp(cmd, "gettimezone") == 0 ) { requestOnChange(GETTIMEZONE, clientId); return; } + if (strcmp(cmd, "getcontrols") == 0 ) { requestOnChange(GETCONTROLS, clientId); return; } + if (strcmp(cmd, "getweather") == 0 ) { requestOnChange(GETWEATHER, clientId); return; } + if (strcmp(cmd, "getactive") == 0 ) { requestOnChange(GETACTIVE, clientId); return; } if (strcmp(cmd, "smartstart") == 0) { - byte valb=atoi(val); - config.store.smartstart=valb==1?1:2; - if(!player.isRunning() && config.store.smartstart==1) config.store.smartstart=0; + byte valb = atoi(val); + config.store.smartstart = valb == 1 ? 1 : 2; + if (!player.isRunning() && config.store.smartstart == 1) config.store.smartstart = 0; config.save(); return; } if (strcmp(cmd, "audioinfo") == 0) { - byte valb=atoi(val); - config.store.audioinfo=valb; + byte valb = atoi(val); + config.store.audioinfo = valb; config.save(); - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); return; } if (strcmp(cmd, "vumeter") == 0) { - byte valb=atoi(val); - config.store.vumeter=valb; + byte valb = atoi(val); + config.store.vumeter = valb; config.save(); - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); return; } if (strcmp(cmd, "softap") == 0) { - byte valb=atoi(val); - config.store.softapdelay=valb; + byte valb = atoi(val); + config.store.softapdelay = valb; config.save(); return; } if (strcmp(cmd, "invertdisplay") == 0) { - byte valb=atoi(val); - config.store.invertdisplay=valb; + byte valb = atoi(val); + config.store.invertdisplay = valb; config.save(); display.invert(); return; } if (strcmp(cmd, "numplaylist") == 0) { - byte valb=atoi(val); - config.store.numplaylist=valb; + byte valb = atoi(val); + config.store.numplaylist = valb; config.save(); - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); return; } - if (strcmp(cmd, "fliptouch") == 0) { - byte valb=atoi(val); - config.store.fliptouch=valb==1; + byte valb = atoi(val); + config.store.fliptouch = valb == 1; config.save(); flipTS(); return; } if (strcmp(cmd, "dbgtouch") == 0) { - byte valb=atoi(val); - config.store.dbgtouch=valb==1; + byte valb = atoi(val); + config.store.dbgtouch = valb == 1; config.save(); return; } if (strcmp(cmd, "flipscreen") == 0) { - byte valb=atoi(val); - config.store.flipscreen=valb; + byte valb = atoi(val); + config.store.flipscreen = valb; config.save(); display.flip(); - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); return; } if (strcmp(cmd, "brightness") == 0) { - byte valb=atoi(val); - if(!config.store.dspon) requestOnChange(DSPON, 0); - config.store.brightness=valb; - //display.setContrast(); + byte valb = atoi(val); + if (!config.store.dspon) requestOnChange(DSPON, 0); + config.store.brightness = valb; config.setBrightness(true); return; } if (strcmp(cmd, "screenon") == 0) { - byte valb=atoi(val); - //config.store.dspon=valb==1; - //config.setBrightness(true); - config.setDspOn(valb==1); + byte valb = atoi(val); + config.setDspOn(valb == 1); return; } if (strcmp(cmd, "contrast") == 0) { - byte valb=atoi(val); - config.store.contrast=valb; + byte valb = atoi(val); + config.store.contrast = valb; config.save(); display.setContrast(); return; } if (strcmp(cmd, "tzh") == 0) { - int vali=atoi(val); - config.store.tzHour=vali; + int vali = atoi(val); + config.store.tzHour = vali; return; } if (strcmp(cmd, "tzm") == 0) { - int vali=atoi(val); - config.store.tzMin=vali; + int vali = atoi(val); + config.store.tzMin = vali; return; } if (strcmp(cmd, "sntp2") == 0) { - strlcpy(config.store.sntp2,val, 35); + strlcpy(config.store.sntp2, val, 35); return; } if (strcmp(cmd, "sntp1") == 0) { - strlcpy(config.store.sntp1,val, 35); - bool tzdone=false; - if(strlen(config.store.sntp1)>0 && strlen(config.store.sntp2)>0){ + strlcpy(config.store.sntp1, val, 35); + bool tzdone = false; + if (strlen(config.store.sntp1) > 0 && strlen(config.store.sntp2) > 0) { configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2); - tzdone=true; - }else if(strlen(config.store.sntp1)>0){ + tzdone = true; + } else if (strlen(config.store.sntp1) > 0) { configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1); - tzdone=true; + tzdone = true; } - if(tzdone){ + if (tzdone) { network.requestTimeSync(true); config.save(); } return; } - if (strcmp(cmd, "volsteps") == 0) { - uint8_t valb=atoi(val); - config.store.volsteps=valb; + uint8_t valb = atoi(val); + config.store.volsteps = valb; config.save(); return; } if (strcmp(cmd, "encacceleration") == 0) { - uint16_t valb=atoi(val); + uint16_t valb = atoi(val); setEncAcceleration(valb); - config.store.encacc=valb; + config.store.encacc = valb; config.save(); return; } if (strcmp(cmd, "irtlp") == 0) { - uint8_t valb=atoi(val); + uint8_t valb = atoi(val); setIRTolerance(valb); return; } if (strcmp(cmd, "showweather") == 0) { - uint8_t valb=atoi(val); - config.store.showweather=valb==1; + uint8_t valb = atoi(val); + config.store.showweather = valb == 1; config.save(); display.showWeather(); #ifdef USE_NEXTION nextion.startWeather(); #endif - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); return; } if (strcmp(cmd, "lat") == 0) { - strlcpy(config.store.weatherlat,val, 10); + strlcpy(config.store.weatherlat, val, 10); return; } if (strcmp(cmd, "lon") == 0) { - strlcpy(config.store.weatherlon,val, 10); + strlcpy(config.store.weatherlon, val, 10); return; } if (strcmp(cmd, "key") == 0) { - strlcpy(config.store.weatherkey,val, 64); + strlcpy(config.store.weatherkey, val, 64); config.save(); display.showWeather(); #ifdef USE_NEXTION nextion.startWeather(); #endif - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); return; } /* 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.store.smartstart = 2; + config.store.audioinfo = false; + config.store.vumeter = false; + config.store.softapdelay = 0; config.save(); - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); - requestOnChange(GETSYSTEM,clientId); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); + requestOnChange(GETSYSTEM, clientId); return; } if (strcmp(val, "screen") == 0) { - config.store.flipscreen=false; + config.store.flipscreen = false; display.flip(); - config.store.invertdisplay=false; + config.store.invertdisplay = false; display.invert(); - config.store.dspon=true; - config.store.brightness=100; + config.store.dspon = true; + config.store.brightness = 100; config.setBrightness(false); - config.store.contrast=55; + config.store.contrast = 55; display.setContrast(); - config.store.numplaylist=false; + config.store.numplaylist = false; config.save(); - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); - requestOnChange(GETSCREEN,clientId); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); + requestOnChange(GETSCREEN, clientId); return; } 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.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(); configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2); network.requestTimeSync(true); - requestOnChange(GETTIMEZONE,clientId); + requestOnChange(GETTIMEZONE, clientId); return; } 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.store.showweather = 0; + strlcpy(config.store.weatherlat, "55.7512", 10); + strlcpy(config.store.weatherlon, "37.6184", 10); + strlcpy(config.store.weatherkey, "", 64); config.save(); display.showWeather(); #ifdef USE_NEXTION nextion.startWeather(); #endif - display.putRequest({NEWMODE, CLEAR}); - display.putRequest({NEWMODE, PLAYER}); - requestOnChange(GETWEATHER,clientId); + display.putRequest({NEWMODE, CLEAR}); display.putRequest({NEWMODE, PLAYER}); + requestOnChange(GETWEATHER, clientId); return; } if (strcmp(val, "controls") == 0) { - config.store.volsteps=1; - config.store.fliptouch=false; - config.store.dbgtouch=false; + config.store.volsteps = 1; + config.store.fliptouch = false; + config.store.dbgtouch = false; setEncAcceleration(200); setIRTolerance(40); - requestOnChange(GETCONTROLS,clientId); + requestOnChange(GETCONTROLS, clientId); return; } - } /* RESETS */ + } /* EOF RESETS */ if (strcmp(cmd, "volume") == 0) { byte v = atoi(val); player.setVol(v, false); } - - /* REMOVE FROM POST - * if (request->hasParam("trebble", true)) { - AsyncWebParameter* pt = request->getParam("trebble", true); - AsyncWebParameter* pm = request->getParam("middle", true); - AsyncWebParameter* pb = request->getParam("bass", true); - int t = atoi(pt->value().c_str()); - int m = atoi(pm->value().c_str()); - int b = atoi(pb->value().c_str()); - //setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass) - player.setTone(b, m, t); - config.setTone(b, m, t); - netserver.requestOnChange(EQUALIZER, 0); - request->send(200); - return; - } - if (request->hasParam("ballance", true)) { - AsyncWebParameter* p = request->getParam("ballance", true); - int b = atoi(p->value().c_str()); - player.setBalance(b); - config.setBalance(b); - netserver.requestOnChange(BALANCE, 0); - request->send(200); - return; - } - */ if (strcmp(cmd, "balance") == 0) { - int8_t valb=atoi(val); + int8_t valb = atoi(val); player.setBalance(valb); config.setBalance(valb); netserver.requestOnChange(BALANCE, 0); return; } if (strcmp(cmd, "treble") == 0) { - int8_t valb=atoi(val); + int8_t valb = atoi(val); player.setTone(config.store.bass, config.store.middle, valb); config.setTone(config.store.bass, config.store.middle, valb); netserver.requestOnChange(EQUALIZER, 0); return; } if (strcmp(cmd, "middle") == 0) { - int8_t valb=atoi(val); + int8_t valb = atoi(val); player.setTone(config.store.bass, valb, config.store.trebble); config.setTone(config.store.bass, valb, config.store.trebble); netserver.requestOnChange(EQUALIZER, 0); return; } if (strcmp(cmd, "bass") == 0) { - int8_t valb=atoi(val); + int8_t valb = atoi(val); player.setTone(valb, config.store.middle, config.store.trebble); config.setTone(valb, config.store.middle, config.store.trebble); netserver.requestOnChange(EQUALIZER, 0); return; } if (strcmp(cmd, "submitplaylist") == 0) { - if(player.isRunning()){ - player.toggle(); - while (player.isRunning()) { - vTaskDelay(10); - } - vTaskDelay(50); - resumePlay=true; - } + // xSemaphoreTake(player.playmutex, portMAX_DELAY); return; } if (strcmp(cmd, "submitplaylistdone") == 0) { - if(resumePlay){ - vTaskDelay(100); - player.toggle(); - resumePlay=false; - } #ifdef MQTT_HOST - mqttPublishPlaylist(); + //mqttPublishPlaylist(); + mqttplaylistticker.attach(5, mqttplaylistSend); #endif + // xSemaphoreGive(player.playmutex); + if (player.isRunning()) { + player.request.station = config.store.lastStation; + player.request.doSave = false; + } return; } #if IR_PIN!=255 if (strcmp(cmd, "irbtn") == 0) { - config.irindex=atoi(val); - irRecordEnable=(config.irindex>=0); - config.irchck=0; + config.irindex = atoi(val); + irRecordEnable = (config.irindex >= 0); + config.irchck = 0; irValsToWs(); - if(config.irindex<0) config.saveIR(); + if (config.irindex < 0) config.saveIR(); } if (strcmp(cmd, "chkid") == 0) { - config.irchck=atoi(val); + config.irchck = atoi(val); } if (strcmp(cmd, "irclr") == 0) { byte cl = atoi(val); - config.ircodes.irVals[config.irindex][cl]=0; + config.ircodes.irVals[config.irindex][cl] = 0; } #endif } } } -void NetServer::setRSSI(int val) { - rssi = val; - //requestOnChange(NRSSI, 0); -} - void NetServer::getPlaylist(uint8_t clientId) { char buf[160] = {0}; sprintf(buf, "{\"file\": \"http://%s%s\"}", WiFi.localIP().toString().c_str(), PLAYLIST_PATH); - if (clientId == 0) { - websocket.textAll(buf); - } else { - websocket.text(clientId, buf); - } - if (resumePlay) { - resumePlay = false; - player.toggle(); - } -} - -bool NetServer::savePlaylist(const char* post) { - File file = SPIFFS.open(PLAYLIST_PATH, "w"); - if (!file) { - return false; - } else { - file.print(post); - file.close(); - vTaskDelay(150); - netserver.requestOnChange(PLAYLISTSAVED, 0); - return true; - } + if (clientId == 0) { websocket.textAll(buf); } else { websocket.text(clientId, buf); } } bool NetServer::importPlaylist() { @@ -708,180 +561,71 @@ bool NetServer::importPlaylist() { void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { char buf[BUFLEN * 2] = { 0 }; switch (request) { - case PLAYLIST: { - getPlaylist(clientId); - break; - } - case PLAYLISTSAVED: { - config.indexPlaylist(); - config.initPlaylist(); - getPlaylist(clientId); -/*#ifdef MQTT_HOST - mqttPublishPlaylist(); -#endif*/ - break; - } + case PLAYLIST: getPlaylist(clientId); break; + case PLAYLISTSAVED: config.indexPlaylist(); config.initPlaylist(); getPlaylist(clientId); break; case GETACTIVE: { bool dbgact = false; - String act="\"group_wifi\","; + String act = "\"group_wifi\","; if (network.status == CONNECTED) { - act+="\"group_system\","; - if(BRIGHTNESS_PIN!=255 || DSP_FLIPPED==1 || DSP_MODEL==DSP_NOKIA5110 || dbgact){ - act+="\"group_display\","; - } + act += "\"group_system\","; + if (BRIGHTNESS_PIN != 255 || DSP_FLIPPED == 1 || DSP_MODEL == DSP_NOKIA5110 || dbgact) act += "\"group_display\","; #ifdef USE_NEXTION - act+="\"group_nextion\","; - if (WEATHER_READY==0 || dbgact){ - act+="\"group_weather\","; - } + act += "\"group_nextion\","; + if (WEATHER_READY == 0 || dbgact) act += "\"group_weather\","; #endif #if defined(LCD_I2C) || DSP_OLED - act+="\"group_oled\","; + act += "\"group_oled\","; #endif - if(VU_READY==1 || dbgact){ - act+="\"group_vu\","; - } - if(BRIGHTNESS_PIN!=255 || dbgact){ - act+="\"group_brightness\","; - } - if(DSP_FLIPPED==1 || dbgact){ - act+="\"group_tft\","; - } - if(TS_CS!=255 || dbgact){ - act+="\"group_touch\","; - } - if(DSP_MODEL==DSP_NOKIA5110){ - act+="\"group_nokia\","; - } - if(DSP_MODEL!=DSP_DUMMY || dbgact){ - act+="\"group_timezone\","; - - } - if (WEATHER_READY==1 || dbgact){ - act+="\"group_weather\","; - } - act+="\"group_controls\","; - if(ENC_BTNL!=255 || ENC2_BTNL!=255 || dbgact){ - act+="\"group_encoder\","; - } - if(IR_PIN!=255 || dbgact){ - act+="\"group_ir\","; - } + if (VU_READY == 1 || dbgact) act += "\"group_vu\","; + if (BRIGHTNESS_PIN != 255 || dbgact) act += "\"group_brightness\","; + if (DSP_FLIPPED == 1 || dbgact) act += "\"group_tft\","; + if (TS_CS != 255 || dbgact) act += "\"group_touch\","; + if (DSP_MODEL == DSP_NOKIA5110) act += "\"group_nokia\","; + if (DSP_MODEL != DSP_DUMMY || dbgact) act += "\"group_timezone\","; + if (WEATHER_READY == 1 || dbgact) act += "\"group_weather\","; + act += "\"group_controls\","; + if (ENC_BTNL != 255 || ENC2_BTNL != 255 || dbgact) act += "\"group_encoder\","; + if (IR_PIN != 255 || dbgact) act += "\"group_ir\","; } - act = act.substring(0, act.length()-1); + act = act.substring(0, act.length() - 1); sprintf (buf, "{\"act\":[%s]}", act.c_str()); break; - } - case GETMODE: { - sprintf (buf, "{\"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); - //playlistrequest = clientId; /* Cleanup this */ - return; - break; - } - case GETSYSTEM: { - sprintf (buf, "{\"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 (buf, "{\"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 (buf, "{\"tzh\":%d,\"tzm\":%d,\"sntp1\":\"%s\",\"sntp2\":\"%s\"}", config.store.tzHour, config.store.tzMin, config.store.sntp1, config.store.sntp2); - break; - } - case GETWEATHER: { - sprintf (buf, "{\"wen\":%d,\"wlat\":\"%s\",\"wlon\":\"%s\",\"wkey\":\"%s\"}", config.store.showweather, config.store.weatherlat, config.store.weatherlon, config.store.weatherkey); - break; - } - case GETCONTROLS: { - sprintf (buf, "{\"vols\":%d,\"enca\":%d,\"irtl\":%d}", config.store.volsteps, config.store.encacc, config.store.irtlp); - break; - } - case DSPON: { - sprintf (buf, "{\"dspontrue\":%d}", 1); - break; - } - case STATION: { - sprintf (buf, "{\"nameset\": \"%s\"}", config.station.name); - requestOnChange(ITEM, clientId); - break; - } - case ITEM: { - sprintf (buf, "{\"current\": %d}", config.store.lastStation); - break; - } - case TITLE: { - sprintf (buf, "{\"meta\": \"%s\"}", config.station.title); - if (player.requestToStart) { - telnet.info(); - player.requestToStart = false; - } else { - telnet.printf("##CLI.META#: %s\n> ", config.station.title); - } - break; - } - case VOLUME: { - sprintf (buf, "{\"vol\": %d}", config.store.volume); -#ifdef MQTT_HOST - if (clientId == 0) mqttPublishVolume(); -#endif - break; - } - case NRSSI: { - sprintf (buf, "{\"rssi\": %d}", rssi); - rssi = 255; - break; - } - case BITRATE: { - sprintf (buf, "{\"bitrate\": %d}", config.station.bitrate); - break; - } - case MODE: { - sprintf (buf, "{\"mode\": \"%s\"}", player.mode == PLAYING ? "playing" : "stopped"); - break; - } - case EQUALIZER: { - sprintf (buf, "{\"bass\": %d, \"middle\": %d, \"trebble\": %d}", config.store.bass, config.store.middle, config.store.trebble); - break; - } - case BALANCE: { - sprintf (buf, "{\"balance\": %d}", config.store.balance); - break; } + case GETMODE: sprintf (buf, "{\"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); return; break; + case GETSYSTEM: sprintf (buf, "{\"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 (buf, "{\"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 (buf, "{\"tzh\":%d,\"tzm\":%d,\"sntp1\":\"%s\",\"sntp2\":\"%s\"}", config.store.tzHour, config.store.tzMin, config.store.sntp1, config.store.sntp2); break; + case GETWEATHER: sprintf (buf, "{\"wen\":%d,\"wlat\":\"%s\",\"wlon\":\"%s\",\"wkey\":\"%s\"}", config.store.showweather, config.store.weatherlat, config.store.weatherlon, config.store.weatherkey); break; + case GETCONTROLS: sprintf (buf, "{\"vols\":%d,\"enca\":%d,\"irtl\":%d}", config.store.volsteps, config.store.encacc, config.store.irtlp); break; + case DSPON: sprintf (buf, "{\"dspontrue\":%d}", 1); break; + case STATION: sprintf (buf, "{\"nameset\": \"%s\"}", config.station.name); requestOnChange(ITEM, clientId); break; + case ITEM: sprintf (buf, "{\"current\": %d}", config.store.lastStation); break; + case TITLE: sprintf (buf, "{\"meta\": \"%s\"}", config.station.title); if (player.requestToStart) { telnet.info(); player.requestToStart = false; } else { telnet.printf("##CLI.META#: %s\n> ", config.station.title); } break; + case VOLUME: sprintf (buf, "{\"vol\": %d}", config.store.volume); break; + case NRSSI: sprintf (buf, "{\"rssi\": %d}", rssi); rssi = 255; break; + case BITRATE: sprintf (buf, "{\"bitrate\": %d}", config.station.bitrate); break; + case MODE: sprintf (buf, "{\"mode\": \"%s\"}", player.mode == PLAYING ? "playing" : "stopped"); break; + case EQUALIZER: sprintf (buf, "{\"bass\": %d, \"middle\": %d, \"trebble\": %d}", config.store.bass, config.store.middle, config.store.trebble); DBGVB("[%s] %s", __func__, buf); break; + case BALANCE: sprintf (buf, "{\"balance\": %d}", config.store.balance); break; } if (strlen(buf) > 0) { - if (clientId == 0) { - websocket.textAll(buf); + if (clientId == 0) { websocket.textAll(buf); }else{ websocket.text(clientId, buf); } #ifdef MQTT_HOST - if (request == STATION || request == ITEM || request == TITLE || request == MODE) mqttPublishStatus(); + if (clientId == 0 && (request == STATION || request == ITEM || request == TITLE || request == MODE)) mqttPublishStatus(); + if (clientId == 0 && request == VOLUME) mqttPublishVolume(); #endif - } else { - websocket.text(clientId, buf); - } } } String processor(const String& var) { // %Templates% - if (var == "VERSION") { - return VERSION; - } + if (var == "VERSION") return VERSION; return String(); } void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { if (!index) { - netserver.takeMallocDog(); + PLOW(); request->_tempFile = SPIFFS.open(TMP_PATH , "w"); } if (len) { @@ -890,130 +634,97 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, } if (final) { request->_tempFile.close(); - netserver.importRequest = true; - request->send(200); + PHIG(); } } void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { switch (type) { - case WS_EVT_CONNECT: - if(config.store.audioinfo) Serial.printf("[WEBSOCKET] client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); - /*netserver.requestOnChange(STATION, client->id()); - netserver.requestOnChange(TITLE, client->id()); - netserver.requestOnChange(VOLUME, client->id()); - netserver.requestOnChange(EQUALIZER, client->id()); - netserver.requestOnChange(BALANCE, client->id()); - netserver.requestOnChange(BITRATE, client->id()); - netserver.requestOnChange(MODE, client->id()); - netserver.playlistrequest = client->id();*/ - - break; - case WS_EVT_DISCONNECT: - if(config.store.audioinfo) Serial.printf("[WEBSOCKET] client #%u disconnected\n", client->id()); - break; - case WS_EVT_DATA: - netserver.onWsMessage(arg, data, len, client->id()); - break; + case WS_EVT_CONNECT: if (config.store.audioinfo) Serial.printf("[WEBSOCKET] client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); break; + case WS_EVT_DISCONNECT: if (config.store.audioinfo) Serial.printf("[WEBSOCKET] client #%u disconnected\n", client->id()); break; + case WS_EVT_DATA: netserver.onWsMessage(arg, data, len, client->id()); break; case WS_EVT_PONG: case WS_EVT_ERROR: break; } } -void handleHTTPPost(AsyncWebServerRequest * request) { - if (request->hasParam("wifisettings", true)) { - AsyncWebParameter* p = request->getParam("wifisettings", true); - if (p->value() != "") { - config.saveWifi(p->value().c_str()); +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) { +#ifdef MQTT_HOST + if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0) while (mqttplaylistblock) vTaskDelay(5); +#endif + netserver.chunkedHtmlPage("application/octet-stream", request, request->url().c_str()); + return; + } + if (strcmp(request->url().c_str(), "/") == 0 && request->params() == 0) { + netserver.chunkedHtmlPage(String(), request, network.status == CONNECTED ? "/www/index.html" : "/www/settings.html"); + return; + } + if (strcmp(request->url().c_str(), "/update") == 0 || strcmp(request->url().c_str(), "/settings") == 0 || strcmp(request->url().c_str(), "/ir") == 0) { + char buf[40] = { 0 }; + sprintf(buf, "/www%s.html", request->url().c_str()); + netserver.chunkedHtmlPage(String(), request, buf); + return; } - request->send(200); - return; - } - if (request->hasParam("playlist", true)) { - AsyncWebParameter* p = request->getParam("playlist", true); - netserver.savePlaylist(p->value().c_str()); - request->send(200); - return; - } - if (network.status != CONNECTED) { - request->send(404); - return; - } - if (request->hasParam("start", true)) { - player.request.station = config.store.lastStation; - request->send(200); - return; - } - if (request->hasParam("stop", true)) { - player.mode = STOPPED; - //display.title("[stopped]"); - config.setTitle("[stopped]"); - request->send(200); - return; - } - if (request->hasParam("prev", true)) { - player.prev(); - request->send(200); - return; - } - if (request->hasParam("next", true)) { - player.next(); - request->send(200); - return; - } - if (request->hasParam("volm", true)) { - player.stepVol(false); - request->send(200); - return; - } - if (request->hasParam("volp", true)) { - player.stepVol(true); - request->send(200); - return; - } - if (request->hasParam("vol", true)) { - AsyncWebParameter* p = request->getParam("vol", true); - int v = atoi(p->value().c_str()); - if (v < 0) v = 0; - if (v > 254) v = 254; - player.setVol(v, false); - request->send(200); - return; - } - if (request->hasParam("trebble", true)) { - AsyncWebParameter* pt = request->getParam("trebble", true); - AsyncWebParameter* pm = request->getParam("middle", true); - AsyncWebParameter* pb = request->getParam("bass", true); - int t = atoi(pt->value().c_str()); - int m = atoi(pm->value().c_str()); - int b = atoi(pb->value().c_str()); - //setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass) - player.setTone(b, m, t); - config.setTone(b, m, t); - netserver.requestOnChange(EQUALIZER, 0); - request->send(200); - return; - } - if (request->hasParam("ballance", true)) { - AsyncWebParameter* p = request->getParam("ballance", true); - int b = atoi(p->value().c_str()); - player.setBalance(b); - config.setBalance(b); - netserver.requestOnChange(BALANCE, 0); - request->send(200); - return; - } - if (request->hasParam("playstation", true)) { - AsyncWebParameter* p = request->getParam("playstation", true); - int id = atoi(p->value().c_str()); - if (id < 1) id = 1; - if (id > config.store.countStation) id = config.store.countStation; - player.request.station = id; - player.request.doSave = true; - request->send(200); - return; } + if (network.status == CONNECTED) { + if (request->hasArg("start")) player.request.station = config.store.lastStation; + if (request->hasArg("stop")) { + player.mode = STOPPED; + config.setTitle("[stopped]"); + } + if (request->hasArg("prev")) player.prev(); + if (request->hasArg("next")) player.next(); + if (request->hasArg("volm")) player.stepVol(false); + if (request->hasArg("volp")) player.stepVol(true); - request->send(404); + 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); + AsyncWebParameter* pb = request->getParam("bass", request->method() == HTTP_POST); + int t = atoi(pt->value().c_str()); + int m = atoi(pm->value().c_str()); + int b = atoi(pb->value().c_str()); + player.setTone(b, m, t); + config.setTone(b, m, t); + netserver.requestOnChange(EQUALIZER, 0); + } + if (request->hasArg("ballance")) { + AsyncWebParameter* p = request->getParam("ballance", request->method() == HTTP_POST); + int b = atoi(p->value().c_str()); + player.setBalance(b); + config.setBalance(b); + netserver.requestOnChange(BALANCE, 0); + } + if (request->hasArg("playstation") || request->hasArg("play")) { + AsyncWebParameter* p = request->getParam(request->hasArg("playstation") ? "playstation" : "play", request->method() == HTTP_POST); + int id = atoi(p->value().c_str()); + if (id < 1) id = 1; + if (id > config.store.countStation) id = config.store.countStation; + player.request.station = id; + player.request.doSave = true; + DBGVB("[%s] play=%d", __func__, id); + } + if (request->hasArg("vol")) { + AsyncWebParameter* p = request->getParam("vol", request->method() == HTTP_POST); + int v = atoi(p->value().c_str()); + if (v < 0) v = 0; + if (v > 254) v = 254; + config.store.volume = v; + player.setVol(v, false); + DBGVB("[%s] vol=%d", __func__, v); + } + if (request->params() > 0) { + request->send(200); + return; + } + } else { + if (request->params() > 0) { + request->send(404); + return; + } + } } diff --git a/yoRadio/netserver.h b/yoRadio/netserver.h index 437e599..914faf6 100644 --- a/yoRadio/netserver.h +++ b/yoRadio/netserver.h @@ -6,38 +6,38 @@ #include "AsyncUDP.h" enum requestType_e : uint8_t { PLAYLIST=1, STATION=2, ITEM=3, TITLE=4, VOLUME=5, NRSSI=6, BITRATE=7, MODE=8, EQUALIZER=9, BALANCE=10, PLAYLISTSAVED=11, GETMODE=12, GETINDEX=13, GETACTIVE=14, GETSYSTEM=15, GETSCREEN=16, GETTIMEZONE=17, GETWEATHER=18, GETCONTROLS=19, DSPON=20 }; -enum htmlPath_e : uint8_t { PINDEX=1, PSETTINGS=2, PUPDATE=3, PIR=4, PPLAYLIST=5, PSSIDS=6 }; +enum import_e : uint8_t { IMDONE=0, IMPL=1, IMWIFI=2 }; + +#define PLOW() //player.setBufsize(1600*2, -1); vTaskDelay(150) +#define PHIG() //vTaskDelay(150); player.setBufsize(1600*AUDIOBUFFER_MULTIPLIER2, -1) class NetServer { public: - uint8_t playlistrequest; // ClientId want the playlist - bool importRequest; + //uint8_t playlistrequest; // ClientId want the playlist/* Cleanup this */ + import_e importRequest; bool resumePlay; - htmlPath_e htmlPath; + char chunkedPathBuffer[40]; public: NetServer() {}; bool begin(); void loop(); void requestOnChange(requestType_e request, uint8_t clientId); - void setRSSI(int val); + void setRSSI(int val) { rssi = val; }; + void chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request, const char * path, bool gzip = false); void onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t clientId); - bool savePlaylist(const char* post); - void takeMallocDog(); - void giveMallocDog(); - uint32_t max, htmlpos; - bool theend; #if IR_PIN!=255 bool irRecordEnable; void irToWs(const char* protocol, uint64_t irvalue); - void irValsToWs(); - void chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request); + void irValsToWs(); #endif private: requestType_e request; int rssi; - void getPlaylist(uint8_t clientId); bool importPlaylist(); + static size_t chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t index); + static void beginUpload(AsyncWebServerRequest *request); + static void beginUpdate(AsyncWebServerRequest *request); }; extern NetServer netserver; diff --git a/yoRadio/options.h b/yoRadio/options.h index a216f1f..63d0fc6 100644 --- a/yoRadio/options.h +++ b/yoRadio/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define VERSION "0.7.414" +#define VERSION "0.7.490" /******************************************************* DO NOT EDIT THIS FILE. diff --git a/yoRadio/player.cpp b/yoRadio/player.cpp index f200d01..40810b8 100644 --- a/yoRadio/player.cpp +++ b/yoRadio/player.cpp @@ -61,7 +61,10 @@ void Player::stopInfo() { void Player::loop() { if (mode == PLAYING) { + xSemaphoreTake(playmutex, portMAX_DELAY); Audio::loop(); + xSemaphoreGive(playmutex); + vTaskDelay(2); } else { if (isRunning()) { //digitalWrite(LED_BUILTIN, LOW); @@ -71,7 +74,6 @@ void Player::loop() { //stopSong(); setDefaults(); stopInfo(); - xSemaphoreGive(playmutex); if (player_on_stop_play) player_on_stop_play(); } } @@ -112,8 +114,6 @@ void Player::setOutputPins(bool isPlaying) { void Player::play(uint16_t stationId) { //stopSong(); - xSemaphoreGive(playmutex); - xSemaphoreTake(playmutex, portMAX_DELAY); setDefaults(); setOutputPins(false); config.setTitle("[connecting]"); diff --git a/yoRadio/src/audioI2S/AudioEx.h b/yoRadio/src/audioI2S/AudioEx.h index 6236d31..5d6ab3f 100644 --- a/yoRadio/src/audioI2S/AudioEx.h +++ b/yoRadio/src/audioI2S/AudioEx.h @@ -32,8 +32,8 @@ #include #endif // SDFATFS_USED -#ifndef AUDIOBUFFER_MULTIPLIER -#define AUDIOBUFFER_MULTIPLIER 12 +#ifndef AUDIOBUFFER_MULTIPLIER2 +#define AUDIOBUFFER_MULTIPLIER2 8 #endif #ifdef SDFATFS_USED @@ -140,7 +140,7 @@ public: protected: size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes //size_t m_buffSizeRAM = 1600 * 5; - size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER; + size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER2; size_t m_buffSize = 0; size_t m_freeSpace = 0; size_t m_writeSpace = 0; diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp index 52fb031..f9ff3ef 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp @@ -7,7 +7,9 @@ * Updated on: Aug 15.2022 * Author: Wolle */ - +#ifndef VS_PATCH_ENABLE +#define VS_PATCH_ENABLE true +#endif #include "audioVS1053Ex.h" //--------------------------------------------------------------------------------------------------------------------- @@ -325,7 +327,7 @@ void Audio::begin(){ setVUmeter(); m_endFillByte = wram_read(0x1E06) & 0xFF; // printDetails("After last clocksetting \n"); - loadUserCode(); // load in VS1053B if you want to play flac + if(VS_PATCH_ENABLE) loadUserCode(); // load in VS1053B if you want to play flac startSong(); } //--------------------------------------------------------------------------------------------------------------------- @@ -1613,6 +1615,7 @@ void Audio::setDefaults(){ * \n The VU meter takes about 0.2MHz of processing power with 48 kHz samplerate. */ void Audio::setVUmeter() { + if(!VS_PATCH_ENABLE) return; uint16_t MP3Status = read_register(SCI_STATUS); if(MP3Status==0) { Serial.println("VS1053 Error: Unable to write SCI_STATUS"); @@ -1636,6 +1639,7 @@ void Audio::setVUmeter() { * \warning This feature is only available with patches that support VU meter. */ void Audio::getVUlevel() { + if(!VS_PATCH_ENABLE) return; if(!_vuInitalized) return; int16_t reg = read_register(SCI_AICTRL3); uint8_t rl = map((uint8_t)reg, 85, 92, 0, 255); diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.h b/yoRadio/src/audioVS1053/audioVS1053Ex.h index d9b17c5..b7020ba 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.h +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.h @@ -9,8 +9,8 @@ #ifndef _vs1053_ext #define _vs1053_ext -#ifndef AUDIOBUFFER_MULTIPLIER -#define AUDIOBUFFER_MULTIPLIER 12 +#ifndef AUDIOBUFFER_MULTIPLIER2 +#define AUDIOBUFFER_MULTIPLIER2 10 #endif #define VS1053VOLM 128 // 128 or 96 only @@ -97,7 +97,7 @@ public: protected: const size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes //const size_t m_buffSizeRAM = 1600 * 10; - const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER; + const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER2; size_t m_buffSize = 0; size_t m_freeSpace = 0; size_t m_writeSpace = 0; diff --git a/yoRadio/src/displays/nextion.cpp b/yoRadio/src/displays/nextion.cpp index 5d55817..e4beb6c 100644 --- a/yoRadio/src/displays/nextion.cpp +++ b/yoRadio/src/displays/nextion.cpp @@ -353,7 +353,7 @@ void Nextion::loop() { wifisettings+=(String(scanBuf)+"\n"); } if (sscanf(rxbuf, "wifidone=%d", &scanDigit) == 1){ - config.saveWifi(wifisettings.c_str()); + config.saveWifiFromNextion(wifisettings.c_str()); } } }