This commit is contained in:
e2002
2025-08-02 15:36:25 +03:00
parent 53cddf3c1d
commit 8b1e0a3d25
15 changed files with 72 additions and 40 deletions

View File

@@ -234,6 +234,14 @@ Work is in progress...
--- ---
## Version history ## Version history
### 0.9.561
**!!! a [full update](#update-over-web-interface) with Sketch data upload is required !!!**\
or-> just upload `yoRadio/data/www/script.js.gz` to Webboard Uploader http://radioipaddr/webboard\
After updating please clear browser cache.
- fixed error when switching to SD Card mode
- fixed issue causing random reboots
- fixed preview playback bug in Playlist Editor
### 0.9.555 ### 0.9.555
- fixed error "assert failed: udp_new_ip_type /IDF/components/lwip/lwip/src/core/udp.c:1278 (Required to lock TCPIP core functionality!)"\ - fixed error "assert failed: udp_new_ip_type /IDF/components/lwip/lwip/src/core/udp.c:1278 (Required to lock TCPIP core functionality!)"\
part #2 part #2

Binary file not shown.

View File

@@ -1225,12 +1225,14 @@ AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(uint8_t * data, size_t
void AsyncWebSocket::_cleanBuffers() void AsyncWebSocket::_cleanBuffers()
{ {
AsyncWebLockGuard l(_lock); AsyncWebLockGuard l(_lock);
while (_buffers.remove_first([](AsyncWebSocketMessageBuffer* b) {
for(AsyncWebSocketMessageBuffer * c: _buffers){ return b && b->canDelete();
}));
/*for(AsyncWebSocketMessageBuffer * c: _buffers){
if(c && c->canDelete()){ if(c && c->canDelete()){
_buffers.remove(c); _buffers.remove(c);
} }
} }*/
} }
AsyncWebSocket::AsyncWebSocketClientLinkedList AsyncWebSocket::getClients() const { AsyncWebSocket::AsyncWebSocketClientLinkedList AsyncWebSocket::getClients() const {

View File

@@ -86,9 +86,8 @@ class AsyncWebSocketMessageBuffer {
private: private:
uint8_t * _data; uint8_t * _data;
size_t _len; size_t _len;
bool _lock; volatile bool _lock;
uint32_t _count; uint32_t _count;
public: public:
AsyncWebSocketMessageBuffer(); AsyncWebSocketMessageBuffer();
AsyncWebSocketMessageBuffer(size_t size); AsyncWebSocketMessageBuffer(size_t size);

View File

@@ -1717,7 +1717,6 @@ void Audio::setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl){
void Audio::connectTask(void* pvParams) { void Audio::connectTask(void* pvParams) {
ConnectParams* params = static_cast<ConnectParams*>(pvParams); ConnectParams* params = static_cast<ConnectParams*>(pvParams);
Audio* self = params->instance; Audio* self = params->instance;
bool res = true;
if(self->_client){ if(self->_client){
self->_connectionResult = self->_client->connect(params->hostwoext, params->port/*, self->m_f_ssl ? self->m_timeout_ms_ssl : self->m_timeout_ms*/); self->_connectionResult = self->_client->connect(params->hostwoext, params->port/*, self->m_f_ssl ? self->m_timeout_ms_ssl : self->m_timeout_ms*/);
}else{ }else{

View File

@@ -175,8 +175,10 @@ void Config::changeMode(int newmode){
if(getMode()==PM_SDCARD){ if(getMode()==PM_SDCARD){
if(pir) player.sendCommand({PR_STOP, 0}); if(pir) player.sendCommand({PR_STOP, 0});
display.putRequest(NEWMODE, SDCHANGE); display.putRequest(NEWMODE, SDCHANGE);
#ifdef NETSERVER_LOOP1
while(display.mode()!=SDCHANGE) while(display.mode()!=SDCHANGE)
delay(10); delay(10);
#endif
delay(50); delay(50);
} }
if(getMode()==PM_WEB) { if(getMode()==PM_WEB) {
@@ -222,6 +224,11 @@ bool Config::spiffsCleanup(){
return ret; return ret;
} }
void Config::waitConnection(){
while(!player.connproc) vTaskDelay(50);
vTaskDelay(500);
}
char * Config::ipToStr(IPAddress ip){ char * Config::ipToStr(IPAddress ip){
snprintf(ipBuf, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); snprintf(ipBuf, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
return ipBuf; return ipBuf;

View File

@@ -280,6 +280,7 @@ class Config {
#endif #endif
void resetSystem(const char *val, uint8_t clientId); void resetSystem(const char *val, uint8_t clientId);
bool spiffsCleanup(); bool spiffsCleanup();
void waitConnection();
char * ipToStr(IPAddress ip); char * ipToStr(IPAddress ip);
bool prepareForPlaying(uint16_t stationId); bool prepareForPlaying(uint16_t stationId);
void configPostPlaying(uint16_t stationId); void configPostPlaying(uint16_t stationId);

View File

@@ -22,6 +22,16 @@ Nextion nextion;
#ifndef DSP_TASK_CORE_ID #ifndef DSP_TASK_CORE_ID
#define DSP_TASK_CORE_ID 0 #define DSP_TASK_CORE_ID 0
#endif #endif
#ifndef DSP_TASK_DELAY
#define DSP_TASK_DELAY pdMS_TO_TICKS(10) // cap for 50 fps
#endif
#define DSP_QUEUE_TICKS 0
#ifndef DSQ_SEND_DELAY
//#define DSQ_SEND_DELAY portMAX_DELAY
#define DSQ_SEND_DELAY pdMS_TO_TICKS(200)
#endif
QueueHandle_t displayQueue; QueueHandle_t displayQueue;
@@ -29,17 +39,20 @@ static void loopDspTask(void * pvParameters){
while(true){ while(true){
#ifndef DUMMYDISPLAY #ifndef DUMMYDISPLAY
if(displayQueue==NULL) break; if(displayQueue==NULL) break;
netserver.loop(); if(timekeeper.loop0()){
if(timekeeper.loop0())
display.loop(); display.loop();
// will NOT delay here, would use message dequeue timeout instead #ifndef NETSERVER_LOOP1
//vTaskDelay(DSP_TASK_DELAY);
#else
netserver.loop(); netserver.loop();
timekeeper.loop0();
vTaskDelay(10);
#endif #endif
} }
#else
timekeeper.loop0();
#ifndef NETSERVER_LOOP1
netserver.loop();
#endif
#endif
vTaskDelay(DSP_TASK_DELAY);
}
vTaskDelete( NULL ); vTaskDelete( NULL );
} }
@@ -53,18 +66,6 @@ DspCore dsp;
Page *pages[] = { new Page(), new Page(), new Page(), new Page() }; Page *pages[] = { new Page(), new Page(), new Page(), new Page() };
#ifndef DSQ_SEND_DELAY
//#define DSQ_SEND_DELAY portMAX_DELAY
#define DSQ_SEND_DELAY pdMS_TO_TICKS(200)
#endif
#ifndef DSP_TASK_DELAY
#define DSP_TASK_DELAY pdMS_TO_TICKS(20) // cap for 50 fps
#endif
// will use DSP_QUEUE_TICKS as delay interval for display task runner when there are no msgs in a queue to process
#define DSP_QUEUE_TICKS DSP_TASK_DELAY
#if !((DSP_MODEL==DSP_ST7735 && DTYPE==INITR_BLACKTAB) || DSP_MODEL==DSP_ST7789 || DSP_MODEL==DSP_ST7796 || DSP_MODEL==DSP_ILI9488 || DSP_MODEL==DSP_ILI9486 || DSP_MODEL==DSP_ILI9341 || DSP_MODEL==DSP_ILI9225) #if !((DSP_MODEL==DSP_ST7735 && DTYPE==INITR_BLACKTAB) || DSP_MODEL==DSP_ST7789 || DSP_MODEL==DSP_ST7796 || DSP_MODEL==DSP_ILI9488 || DSP_MODEL==DSP_ILI9486 || DSP_MODEL==DSP_ILI9341 || DSP_MODEL==DSP_ILI9225)
#undef BITRATE_FULL #undef BITRATE_FULL
#define BITRATE_FULL false #define BITRATE_FULL false
@@ -397,7 +398,7 @@ void Display::loop() {
_bootScreen(); _bootScreen();
return; return;
} }
if(displayQueue==NULL) return; if(displayQueue==NULL || _locked) return;
_pager.loop(); _pager.loop();
#ifdef USE_NEXTION #ifdef USE_NEXTION
nextion.loop(); nextion.loop();

View File

@@ -37,6 +37,8 @@ class Display {
void wakeup(); void wakeup();
void setContrast(); void setContrast();
void printPLitem(uint8_t pos, const char* item); void printPLitem(uint8_t pos, const char* item);
void lock() { _locked=true; }
void unlock() { _locked=false; }
private: private:
ScrollWidget _meta, _title1, _plcurrent; ScrollWidget _meta, _title1, _plcurrent;
ScrollWidget *_weather; ScrollWidget *_weather;
@@ -52,6 +54,7 @@ class Display {
ClockWidget _clock; ClockWidget _clock;
Page *_boot; Page *_boot;
TextWidget *_bootstring, *_volip, *_voltxt, *_rssi, *_bitrate; TextWidget *_bootstring, *_volip, *_voltxt, *_rssi, *_bitrate;
bool _locked = false;
uint8_t _bootStep; uint8_t _bootStep;
void _time(bool redraw = false); void _time(bool redraw = false);
void _apScreen(); void _apScreen();

View File

@@ -12,7 +12,7 @@ TimerHandle_t mqttReconnectTimer;
char topic[100], status[BUFLEN+50]; char topic[100], status[BUFLEN+50];
void connectToMqtt() { void connectToMqtt() {
while(!player.connproc) vTaskDelay(50); //config.waitConnection();
mqttClient.connect(); mqttClient.connect();
} }

View File

@@ -11,7 +11,7 @@
#include "commandhandler.h" #include "commandhandler.h"
#include "timekeeper.h" #include "timekeeper.h"
#include <Update.h> #include <Update.h>
#include <ESPmDNS.h>
//#include <Ticker.h> //#include <Ticker.h>
#ifdef USE_SD #ifdef USE_SD
@@ -21,7 +21,12 @@
#define MIN_MALLOC 24112 #define MIN_MALLOC 24112
#endif #endif
#ifndef NSQ_SEND_DELAY #ifndef NSQ_SEND_DELAY
#define NSQ_SEND_DELAY pdMS_TO_TICKS(100) //portMAX_DELAY? //#define NSQ_SEND_DELAY portMAX_DELAY
#define NSQ_SEND_DELAY pdMS_TO_TICKS(300)
#endif
#ifndef NS_QUEUE_TICKS
//#define NS_QUEUE_TICKS pdMS_TO_TICKS(2)
#define NS_QUEUE_TICKS 0
#endif #endif
//#define CORS_DEBUG //Enable CORS policy: 'Access-Control-Allow-Origin' (for testing) //#define CORS_DEBUG //Enable CORS policy: 'Access-Control-Allow-Origin' (for testing)
@@ -72,8 +77,8 @@ bool NetServer::begin(bool quiet) {
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), F("content-type")); DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), F("content-type"));
#endif #endif
webserver.begin(); webserver.begin();
if(strlen(config.store.mdnsname)>0) //if(strlen(config.store.mdnsname)>0)
MDNS.begin(config.store.mdnsname); // MDNS.begin(config.store.mdnsname);
websocket.onEvent(onWsEvent); websocket.onEvent(onWsEvent);
webserver.addHandler(&websocket); webserver.addHandler(&websocket);
if(!quiet) Serial.println("done"); if(!quiet) Serial.println("done");
@@ -93,10 +98,12 @@ size_t NetServer::chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t
size_t needread = filesize - index; size_t needread = filesize - index;
if (!needread) { if (!needread) {
requiredfile.close(); requiredfile.close();
display.unlock();
return 0; return 0;
} }
size_t canread = (needread > maxLen) ? maxLen : needread; 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); DBGVB("[%s] seek to %d in %s and read %d bytes with maxLen=%d", __func__, index, netserver.chunkedPathBuffer, canread, maxLen);
//netserver.loop();
requiredfile.seek(index, SeekSet); requiredfile.seek(index, SeekSet);
requiredfile.read(buffer, canread); requiredfile.read(buffer, canread);
index += canread; index += canread;
@@ -108,6 +115,9 @@ void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest
memset(chunkedPathBuffer, 0, sizeof(chunkedPathBuffer)); memset(chunkedPathBuffer, 0, sizeof(chunkedPathBuffer));
strlcpy(chunkedPathBuffer, path, sizeof(chunkedPathBuffer)-1); strlcpy(chunkedPathBuffer, path, sizeof(chunkedPathBuffer)-1);
AsyncWebServerResponse *response; AsyncWebServerResponse *response;
#ifndef NETSERVER_LOOP1
display.lock();
#endif
response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback); response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback);
response->addHeader("Cache-Control","max-age=31536000"); response->addHeader("Cache-Control","max-age=31536000");
request->send(response); request->send(response);
@@ -124,10 +134,6 @@ void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest
#define SHOW_WEATHER false #define SHOW_WEATHER false
#endif #endif
#ifndef NS_QUEUE_TICKS
#define NS_QUEUE_TICKS 2
#endif
const char *getFormat(BitrateFormat _format) { const char *getFormat(BitrateFormat _format) {
switch (_format) { switch (_format) {
case BF_MP3: return "MP3"; case BF_MP3: return "MP3";
@@ -308,13 +314,14 @@ void NetServer::loop() {
delay(100); delay(100);
ESP.restart(); ESP.restart();
} }
processQueue();
websocket.cleanupClients(); websocket.cleanupClients();
switch (importRequest) { switch (importRequest) {
case IMPL: importPlaylist(); importRequest = IMDONE; break; case IMPL: importPlaylist(); importRequest = IMDONE; break;
case IMWIFI: config.saveWifi(); importRequest = IMDONE; break; case IMWIFI: config.saveWifi(); importRequest = IMDONE; break;
default: break; default: break;
} }
processQueue(); //processQueue();
} }
#if IR_PIN!=255 #if IR_PIN!=255

View File

@@ -7,6 +7,7 @@
#include "player.h" #include "player.h"
#include "mqtt.h" #include "mqtt.h"
#include "timekeeper.h" #include "timekeeper.h"
#include <ESPmDNS.h>
#ifndef WIFI_ATTEMPTS #ifndef WIFI_ATTEMPTS
#define WIFI_ATTEMPTS 16 #define WIFI_ATTEMPTS 16
@@ -154,6 +155,8 @@ void MyNetwork::setWifiParams(){
WiFi.onEvent(WiFiReconnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); WiFi.onEvent(WiFiReconnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
WiFi.onEvent(WiFiLostConnection, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); WiFi.onEvent(WiFiLostConnection, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
//config.setTimeConf(); //?? //config.setTimeConf(); //??
if(strlen(config.store.mdnsname)>0)
MDNS.begin(config.store.mdnsname);
} }
void MyNetwork::requestTimeSync(bool withTelnetOutput, uint8_t clientId) { void MyNetwork::requestTimeSync(bool withTelnetOutput, uint8_t clientId) {

View File

@@ -1,7 +1,7 @@
#ifndef options_h #ifndef options_h
#define options_h #define options_h
#define YOVERSION "0.9.555" #define YOVERSION "0.9.561"
/******************************************************* /*******************************************************
DO NOT EDIT THIS FILE. DO NOT EDIT THIS FILE.

View File

@@ -206,6 +206,7 @@ void TimeKeeper::_upSDPos(){
void TimeKeeper::timeTask(){ void TimeKeeper::timeTask(){
static uint8_t tsFailCnt = 0; static uint8_t tsFailCnt = 0;
config.waitConnection();
if(getLocalTime(&network.timeinfo)){ if(getLocalTime(&network.timeinfo)){
tsFailCnt = 0; tsFailCnt = 0;
forceTimeSync = false; forceTimeSync = false;
@@ -226,8 +227,8 @@ void TimeKeeper::timeTask(){
} }
} }
void TimeKeeper::weatherTask(){ void TimeKeeper::weatherTask(){
if(!weatherBuf || strlen(config.store.weatherkey)==0 || !config.store.showweather) return;
forceWeather = false; forceWeather = false;
if(!weatherBuf || strlen(config.store.weatherkey)==0 || !config.store.showweather) return;
_getWeather(); _getWeather();
} }
@@ -328,7 +329,7 @@ bool _getWeather() {
} }
}, NULL); // <-- client->onData }, NULL); // <-- client->onData
}, NULL); // <-- weatherClient->onConnect }, NULL); // <-- weatherClient->onConnect
while(!player.connproc) vTaskDelay(50); config.waitConnection();
if(!weatherClient->connect(host, 80)){ if(!weatherClient->connect(host, 80)){
Serial.println("##WEATHER###: connection failed"); Serial.println("##WEATHER###: connection failed");
AsyncClient * client = weatherClient; AsyncClient * client = weatherClient;

View File

@@ -99,7 +99,6 @@ void setup() {
if (config.getMode()==PM_SDCARD) player.initHeaders(config.station.url); if (config.getMode()==PM_SDCARD) player.initHeaders(config.station.url);
player.lockOutput=false; player.lockOutput=false;
if (config.store.smartstart == 1) { if (config.store.smartstart == 1) {
delay(250);
player.sendCommand({PR_PLAY, config.lastStation()}); player.sendCommand({PR_PLAY, config.lastStation()});
} }
pm.on_end_setup(); pm.on_end_setup();
@@ -115,7 +114,9 @@ void loop() {
#endif #endif
} }
loopControls(); loopControls();
//netserver.loop(); #ifdef NETSERVER_LOOP1
netserver.loop();
#endif
} }
#include "core/audiohandlers.h" #include "core/audiohandlers.h"