v0.9.337b

This commit is contained in:
e2002
2024-11-27 12:43:44 +03:00
parent 778dd1e847
commit 4f1582b7d6
193 changed files with 68179 additions and 593 deletions

View File

@@ -5,16 +5,14 @@
#include "player.h"
#include "network.h"
#include "netserver.h"
#include "spidog.h"
#ifdef USE_SD
#include "sdmanager.h"
#endif
Config config;
#if DSP_HSPI || TS_HSPI || VS_HSPI
SPIClass SPI2(HSPI);
#endif
#if defined(SD_SPIPINS) || SD_HSPI
SPIClass SDSPI(HSPI);
#endif
void u8fix(char *src){
char last = src[strlen(src)-1];
@@ -34,17 +32,16 @@ bool Config::_isFSempty() {
void Config::init() {
EEPROM.begin(EEPROM_SIZE);
sdog.begin();
bootInfo();
#if RTCSUPPORTED
_rtcFound = false;
BOOTLOG("RTC begin(SDA=%d,SCL=%d)", RTC_SDA, RTC_SCL);
if(rtc.init()){
BOOTLOG("done");
_rtcFound = true;
}else{
BOOTLOG("[ERROR] - Couldn't find RTC");
}
_rtcFound = false;
BOOTLOG("RTC begin(SDA=%d,SCL=%d)", RTC_SDA, RTC_SCL);
if(rtc.init()){
BOOTLOG("done");
_rtcFound = true;
}else{
BOOTLOG("[ERROR] - Couldn't find RTC");
}
#endif
emptyFS = true;
#if IR_PIN!=255
@@ -74,8 +71,12 @@ void Config::init() {
emptyFS = _isFSempty();
if(emptyFS) BOOTLOG("SPIFFS is empty!");
ssidsCount = 0;
_cardStatus = CS_NONE;
_SDplaylistFS = getMode()==PM_SDCARD?&SD:(true?&SPIFFS:_SDplaylistFS);
//!!_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;
@@ -85,36 +86,10 @@ void Config::init() {
}
#ifdef USE_SD
bool Config::_sdCardIsConnected() {
sdog.takeMutex();
if(SD.sectorSize()<1) {
sdog.giveMutex();
return false;
}
uint8_t buff[SD.sectorSize()] = { 0 };
bool bread = SD.readRAW(buff, 1);
if(SD.sectorSize()>0 && !bread) SD.end();
sdog.giveMutex();
return bread;
}
bool Config::_sdBegin(){
bool out = false;
#if SDC_CS!=255
sdog.takeMutex();
#if defined(SD_SPIPINS) || SD_HSPI
out = SD.begin(SDC_CS, SDSPI);
#else
out = SD.begin(SDC_CS);
#endif
sdog.giveMutex();
#endif
return out;
}
/*
void Config::checkSD(){
cardStatus_e prevCardStatus = _cardStatus;
if(_sdCardIsConnected()){
if(sdman.cardPresent()){
if(_cardStatus==CS_NONE || _cardStatus==CS_PRESENT || _cardStatus==CS_EJECTED) {
_cardStatus=CS_PRESENT;
}else{
@@ -129,37 +104,18 @@ void Config::checkSD(){
backupSDStation = 0;
}
}
void Config::_mountSD(){
if(display.mode()==SDCHANGE) return;
sdog.takeMutex(); uint16_t ssz = SD.sectorSize(); sdog.giveMutex();
if(ssz<1) SDinit = _sdBegin();
if(!_sdCardIsConnected()) {
if(getMode()==PM_SDCARD){
SDinit = false;
}
}else{
if(!SDinit){
if(!_sdBegin()){
Serial.println("##[ERROR]#\tCard Mount Failed");
}else{
SDinit = true;
}
}
}
}
*/
void Config::changeMode(int newmode){
if(SDC_CS==255) return;
if(network.status==SOFT_AP || display.mode()==LOST){
store.play_mode=PM_SDCARD;
save();
delay(50);
ESP.restart();
store.play_mode=PM_SDCARD;
save();
delay(50);
ESP.restart();
}
if(!SDinit) {
_mountSD();
if(!SDinit){
if(!sdman.ready) {
sdman.mount();
if(!sdman.ready){
Serial.println("##[ERROR]#\tSD Not Found");
netserver.requestOnChange(GETPLAYERMODE, 0);
return;
@@ -175,8 +131,8 @@ void Config::changeMode(int newmode){
store.play_mode=(playMode_e)newmode;
}
save();
_SDplaylistFS = getMode()==PM_SDCARD?&SD:(true?&SPIFFS:_SDplaylistFS);
if(getMode()==PM_SDCARD && _cardStatus!=CS_MOUNTED){
_SDplaylistFS = getMode()==PM_SDCARD?&sdman:(true?&SPIFFS:_SDplaylistFS);
if(getMode()==PM_SDCARD && sdman.status()!=CS_MOUNTED){
display.putRequest(NEWMODE, SDCHANGE);
while(display.mode()!=SDCHANGE)
delay(10);
@@ -196,99 +152,20 @@ void Config::changeMode(int newmode){
display.putRequest(NEWSTATION);
}
bool endsWith (const char* base, const char* str) {
int slen = strlen(str) - 1;
const char *p = base + strlen(base) - 1;
while(p > base && isspace(*p)) p--;
p -= slen;
if (p < base) return false;
return (strncmp(p, str, slen) == 0);
}
uint32_t sdFCount;
void Config::listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels){
sdog.takeMutex(); File root = SD.open(dirname); sdog.giveMutex();
if(!root){
Serial.println("##[ERROR]#\tFailed to open directory");
return;
}
sdog.takeMutex();
if(!root.isDirectory()){
Serial.println("##[ERROR]#\tNot a directory");
sdog.giveMutex();
return;
}
sdog.giveMutex();
sdog.takeMutex(); File file = root.openNextFile(); sdog.giveMutex();
uint32_t pos = 0;
while(file){
vTaskDelay(2);
sdog.takeMutex();
bool fid = file.isDirectory();
const char * fp = file.path();
const char * fn = file.name();
sdog.giveMutex();
if(fid){
if(levels && !checkNoMedia(fp)){
listSD(plSDfile, plSDindex, fp, levels -1);
}
} else {
if(endsWith(strlwr((char*)fn), ".mp3") || endsWith(fn, ".m4a") || endsWith(fn, ".aac") || endsWith(fn, ".wav") || endsWith(fn, ".flac")){
sdog.takeMutex();
pos = plSDfile.position();
plSDfile.print(fn); plSDfile.print("\t"); plSDfile.print(fp); plSDfile.print("\t"); plSDfile.println(0);
plSDindex.write((byte *) &pos, 4);
sdog.giveMutex();
Serial.print(".");
if(display.mode()==SDCHANGE) display.putRequest(SDFILEINDEX, sdFCount+1);
sdFCount++;
if(sdFCount%64==0) Serial.println();
}
}
sdog.takeMutex(); if(file) file.close(); file = root.openNextFile(); sdog.giveMutex();
}
sdog.takeMutex(); if(root) root.close(); sdog.giveMutex();
}
void Config::indexSDPlaylist() {
sdFCount = 0;
sdog.takeMutex();
if(SDPLFS()->exists(PLAYLIST_SD_PATH)) SDPLFS()->remove(PLAYLIST_SD_PATH);
if(SDPLFS()->exists(INDEX_SD_PATH)) SDPLFS()->remove(INDEX_SD_PATH);
File playlist = SDPLFS()->open(PLAYLIST_SD_PATH, "w", true);
sdog.giveMutex();
if (!playlist) {
return;
}
sdog.takeMutex();
File index = SDPLFS()->open(INDEX_SD_PATH, "w", true);
sdog.giveMutex();
listSD(playlist, index, "/", SD_MAX_LEVELS);
sdog.takeMutex();
index.flush();
index.close();
playlist.flush();
playlist.close();
sdog.giveMutex();
Serial.println();
delay(50);
}
void Config::initSDPlaylist(bool doIndex) {
store.countStation = 0;
if(doIndex) indexSDPlaylist();
sdog.takeMutex();
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;
store.lastStation = random(1, store.countStation);
backupSDStation = store.lastStation;
}
index.close();
save();
}
sdog.giveMutex();
}
#endif //#ifdef USE_SD
@@ -303,30 +180,31 @@ bool Config::spiffsCleanup(){
void Config::initPlaylistMode(){
sdResumePos = 0;
SDinit = false;
//SDinit = false;
#ifdef USE_SD
if(!_sdBegin()){
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(_cardStatus!=CS_MOUNTED){
_cardStatus=CS_MOUNTED;
if(sdman.status()!=CS_MOUNTED){
sdman.status(CS_MOUNTED);
if(_bootDone) Serial.println("Waiting for SD card indexing..."); else BOOTLOG("Waiting for SD card indexing...");
initSDPlaylist();
}else{
initSDPlaylist(false);
initSDPlaylist(false);
if(backupSDStation==0) {
store.lastStation = random(1, store.countStation);
backupSDStation = store.lastStation;
}else store.lastStation = backupSDStation;
}
}
SDinit = true;
//SDinit = true;
}
#else
store.play_mode=PM_WEB;
#else //ifdef USE_SD
store.play_mode=PM_WEB;
#endif
if(getMode()==PM_WEB && !emptyFS) initPlaylist();
@@ -395,7 +273,7 @@ void Config::loadTheme(){
}
template <class T> int Config::eepromWrite(int ee, const T& value) {
const byte* p = (const byte*)(const void*)&value;
const uint8_t* p = (const uint8_t*)(const void*)&value;
int i;
for (i = 0; i < sizeof(value); i++)
EEPROM.write(ee++, *p++);
@@ -404,7 +282,7 @@ template <class T> int Config::eepromWrite(int ee, const T& value) {
}
template <class T> int Config::eepromRead(int ee, T& value) {
byte* p = (byte*)(void*)&value;
uint8_t* p = (uint8_t*)(void*)&value;
int i;;
for (i = 0; i < sizeof(value); i++)
*p++ = EEPROM.read(ee++);
@@ -503,7 +381,7 @@ void Config::saveVolume(){
EEPROM.commit();
}
byte Config::setVolume(byte val) {
uint8_t Config::setVolume(uint8_t val) {
store.volume = val;
display.putRequest(DRAWVOL);
netserver.requestOnChange(VOLUME, 0);
@@ -517,7 +395,7 @@ void Config::setTone(int8_t bass, int8_t middle, int8_t trebble) {
save();
}
void Config::setSmartStart(byte ss) {
void Config::setSmartStart(uint8_t ss) {
if (store.smartstart < 2) {
store.smartstart = ss;
save();
@@ -529,19 +407,19 @@ void Config::setBalance(int8_t balance) {
save();
}
byte Config::setLastStation(uint16_t val) {
uint8_t Config::setLastStation(uint16_t val) {
store.lastStation = val;
save();
return store.lastStation;
}
byte Config::setCountStation(uint16_t val) {
uint8_t Config::setCountStation(uint16_t val) {
store.countStation = val;
save();
return store.countStation;
}
byte Config::setLastSSID(byte val) {
uint8_t Config::setLastSSID(uint8_t val) {
store.lastSSID = val;
save();
return store.lastSSID;
@@ -573,7 +451,7 @@ void Config::indexPlaylist() {
while (playlist.available()) {
uint32_t pos = playlist.position();
if (parseCSV(playlist.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) {
index.write((byte *) &pos, 4);
index.write((uint8_t *) &pos, 4);
}
}
index.close();
@@ -591,14 +469,6 @@ void Config::initPlaylist() {
save();
}
}
bool Config::checkNoMedia(const char* path){
char nomedia[BUFLEN]= {0};
strlcat(nomedia, path, BUFLEN);
strlcat(nomedia, "/.nomedia", BUFLEN);
sdog.takeMutex(); bool nm = SD.exists(nomedia); sdog.giveMutex();
return nm;
}
void Config::loadStation(uint16_t ls) {
char sName[BUFLEN], sUrl[BUFLEN];
@@ -613,7 +483,6 @@ void Config::loadStation(uint16_t ls) {
if (ls > store.countStation) {
ls = 1;
}
sdog.takeMutex();
File playlist = SDPLFS()->open(REAL_PLAYL, "r");
File index = SDPLFS()->open(REAL_INDEX, "r");
@@ -633,11 +502,9 @@ void Config::loadStation(uint16_t ls) {
setLastStation(ls);
}
playlist.close();
sdog.giveMutex();
}
char * Config::stationByNum(uint16_t num){
sdog.takeMutex();
File playlist = SDPLFS()->open(REAL_PLAYL, "r");
File index = SDPLFS()->open(REAL_INDEX, "r");
index.seek((num - 1) * 4, SeekSet);
@@ -648,7 +515,6 @@ char * Config::stationByNum(uint16_t num){
playlist.seek(pos, SeekSet);
strncpy(_stationBuf, playlist.readStringUntil('\t').c_str(), BUFLEN/2);
playlist.close();
sdog.giveMutex();
return _stationBuf;
}
@@ -659,10 +525,8 @@ uint8_t Config::fillPlMenu(int from, uint8_t count, bool fromNextion) {
if (store.countStation == 0) {
return 0;
}
sdog.takeMutex();
File playlist = SDPLFS()->open(REAL_PLAYL, "r");
File index = SDPLFS()->open(REAL_INDEX, "r");
sdog.giveMutex();
while (true) {
if (ls < 1) {
ls++;
@@ -674,33 +538,29 @@ uint8_t Config::fillPlMenu(int from, uint8_t count, bool fromNextion) {
continue;
}
if (!finded) {
sdog.takeMutex();
index.seek((ls - 1) * 4, SeekSet);
uint32_t pos;
index.readBytes((char *) &pos, 4);
finded = true;
index.close();
playlist.seek(pos, SeekSet);
sdog.giveMutex();
}
bool pla = true;
while (pla) {
sdog.takeMutex();
pla = playlist.available();
pla = playlist.available();
String stationName = playlist.readStringUntil('\n');
sdog.giveMutex();
stationName = stationName.substring(0, stationName.indexOf('\t'));
if(config.store.numplaylist && stationName.length()>0) stationName = String(from+c)+" "+stationName;
if(!fromNextion) display.printPLitem(c, stationName.c_str());
#ifdef USE_NEXTION
if(fromNextion) nextion.printPLitem(c, stationName.c_str());
#endif
#ifdef USE_NEXTION
if(fromNextion) nextion.printPLitem(c, stationName.c_str());
#endif
c++;
if (c >= count) break;
}
break;
}
sdog.takeMutex();playlist.close();sdog.giveMutex();
playlist.close();
return c;
}
@@ -773,7 +633,7 @@ bool Config::parseJSON(const char* line, char* name, char* url, int &ovol) {
return true;
}
bool Config::parseWsCommand(const char* line, char* cmd, char* val, byte cSize) {
bool Config::parseWsCommand(const char* line, char* cmd, char* val, uint8_t cSize) {
char *tmpe;
tmpe = strstr(line, "=");
if (tmpe == NULL) return false;
@@ -824,7 +684,7 @@ bool Config::initNetwork() {
return false;
}
char ssidval[30], passval[40];
byte c = 0;
uint8_t c = 0;
while (file.available()) {
if (parseSsid(file.readStringUntil('\n').c_str(), ssidval, passval)) {
strlcpy(ssids[c].ssid, ssidval, 30);
@@ -916,8 +776,8 @@ void Config::bootInfo() {
BOOTLOG("esp32core:\t%d.%d.%d", ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH);
uint32_t chipId = 0;
for(int i=0; i<17; i=i+8) {
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
BOOTLOG("chip:\t\tmodel: %s | rev: %d | id: %d | cores: %d | psram: %d", ESP.getChipModel(), ESP.getChipRevision(), chipId, ESP.getChipCores(), ESP.getPsramSize());
BOOTLOG("display:\t%d", DSP_MODEL);
if(VS1053_CS==255) {

View File

@@ -4,7 +4,7 @@
#include <Ticker.h>
#include <SPI.h>
#include <SPIFFS.h>
#include "SD.h"
//#include "SD.h"
#include "options.h"
#include "rtcsupport.h"
@@ -38,10 +38,12 @@
#define MAX_PLAY_MODE 1
#if SDC_CS!=255
#define USE_SD
#define USE_SD
#endif
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
#define ESP_ARDUINO_3 1
#endif
enum playMode_e : uint8_t { PM_WEB=0, PM_SDCARD=1 };
enum cardStatus_e : uint8_t { CS_NONE=0, CS_PRESENT=1, CS_MOUNTED=2, CS_EJECTED=3 };
enum BitrateFormat { BF_UNCNOWN, BF_MP3, BF_AAC, BF_FLAC, BF_OGG, BF_WAV };
void u8fix(char *src);
@@ -79,16 +81,16 @@ struct theme_t {
struct config_t
{
unsigned int config_set; //must be 4262
byte volume;
uint8_t volume;
int8_t balance;
int8_t trebble;
int8_t middle;
int8_t bass;
uint16_t lastStation;
uint16_t countStation;
byte lastSSID;
uint8_t lastSSID;
bool audioinfo;
byte smartstart;
uint8_t smartstart;
int8_t tzHour;
int8_t tzMin;
uint16_t timezoneOffset;
@@ -161,7 +163,7 @@ class Config {
#endif
BitrateFormat configFmt = BF_UNCNOWN;
neworkItem ssids[5];
byte ssidsCount;
uint8_t ssidsCount;
uint16_t sleepfor;
uint32_t sdResumePos;
uint16_t backupLastStation;
@@ -177,32 +179,31 @@ class Config {
#endif
void init();
void loadTheme();
byte setVolume(byte val);
uint8_t setVolume(uint8_t val);
void saveVolume();
void setTone(int8_t bass, int8_t middle, int8_t trebble);
void setBalance(int8_t balance);
byte setLastStation(uint16_t val);
byte setCountStation(uint16_t val);
byte setLastSSID(byte val);
uint8_t setLastStation(uint16_t val);
uint8_t setCountStation(uint16_t val);
uint8_t setLastSSID(uint8_t val);
void setTitle(const char* title);
void setStation(const char* station);
bool parseCSV(const char* line, char* name, char* url, int &ovol);
bool parseJSON(const char* line, char* name, char* url, int &ovol);
bool parseWsCommand(const char* line, char* cmd, char* val, byte cSize);
bool parseWsCommand(const char* line, char* cmd, char* val, uint8_t cSize);
bool parseSsid(const char* line, char* ssid, char* pass);
void loadStation(uint16_t station);
bool initNetwork();
bool saveWifi();
bool saveWifiFromNextion(const char* post);
void setSmartStart(byte ss);
void setSmartStart(uint8_t ss);
void setBitrateFormat(BitrateFormat fmt) { configFmt = fmt; }
void initPlaylist();
void indexPlaylist();
#ifdef USE_SD
void initSDPlaylist(bool doIndex = true);
void indexSDPlaylist();
void changeMode(int newmode=-1);
void checkSD();
void initSDPlaylist(bool doIndex = true);
void changeMode(int newmode=-1);
#endif
uint8_t fillPlMenu(int from, uint8_t count, bool fromNextion=false);
char * stationByNum(uint16_t num);
@@ -217,33 +218,26 @@ class Config {
void setSnuffle(bool sn);
uint8_t getMode() { return store.play_mode & 0b11; }
void initPlaylistMode();
cardStatus_e getSDStatus(){ return _cardStatus; };
void clearCardStatus() { if(_cardStatus!=CS_NONE) _cardStatus=CS_NONE; }
bool spiffsCleanup();
FS* SDPLFS(){ return _SDplaylistFS; }
#if RTCSUPPORTED
bool isRTCFound(){ return _rtcFound; };
bool isRTCFound(){ return _rtcFound; };
#endif
private:
template <class T> int eepromWrite(int ee, const T& value);
template <class T> int eepromRead(int ee, T& value);
cardStatus_e _cardStatus;
bool _bootDone;
#if RTCSUPPORTED
bool _rtcFound;
bool _rtcFound;
#endif
FS* _SDplaylistFS;
void setDefaults();
Ticker _sleepTimer;
static void doSleep();
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
#ifdef USE_SD
void listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels);
bool _sdCardIsConnected();
void _mountSD();
bool _sdBegin();
#endif
bool checkNoMedia(const char* path);
void _initHW();
bool _isFSempty();

View File

@@ -49,13 +49,13 @@ constexpr uint8_t nrOfButtons = sizeof(button) / sizeof(button[0]);
#if IR_PIN!=255
#include <assert.h>
#include <IRrecv.h>
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRtext.h>
#include <IRutils.h>
byte irVolRepeat = 0;
#include "../IRremoteESP8266/IRrecv.h"
#include "../IRremoteESP8266/IRremoteESP8266.h"
#include "../IRremoteESP8266/IRac.h"
#include "../IRremoteESP8266/IRtext.h"
#include "../IRremoteESP8266/IRutils.h"
uint8_t irVolRepeat = 0;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = IR_TIMEOUT;
const uint16_t kMinUnknownSize = 12;
@@ -206,7 +206,7 @@ void encoder2Loop() {
void irBlink() {
if(LED_BUILTIN==255) return;
if (player.status() == STOPPED) {
for (byte i = 0; i < 7; i++) {
for (uint8_t i = 0; i < 7; i++) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(100);
}

View File

@@ -99,8 +99,8 @@ class Display {
void loop(){}
bool ready() { return true; }
void resetQueue(){}
void centerText(const char* text, byte y, uint16_t fg, uint16_t bg){}
void rightText(const char* text, byte y, uint16_t fg, uint16_t bg){}
void centerText(const char* text, uint8_t y, uint16_t fg, uint16_t bg){}
void rightText(const char* text, uint8_t y, uint16_t fg, uint16_t bg){}
void flip(){}
void invert(){}
void setContrast(){}

View File

@@ -10,8 +10,9 @@
#include "mqtt.h"
#include "controls.h"
#include <Update.h>
#include "spidog.h"
#ifdef USE_SD
#include "sdmanager.h"
#endif
#ifndef MIN_MALLOC
#define MIN_MALLOC 24112
#endif
@@ -19,13 +20,6 @@
#define NSQ_SEND_DELAY (TickType_t)100 //portMAX_DELAY?
#endif
#ifdef USE_SD
#define CARDLOCK() sdog.tm()
#define CARDUNLOCK() sdog.gm()
#else
#define CARDLOCK() {}
#define CARDUNLOCK() {}
#endif
//#define CORS_DEBUG
NetServer netserver;
@@ -167,30 +161,24 @@ 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){
CARDLOCK();
requiredfile = config.SDPLFS()->open(netserver.chunkedPathBuffer, "r");
CARDUNLOCK();
}else{
requiredfile = SPIFFS.open(netserver.chunkedPathBuffer, "r");
}
if (!requiredfile) return 0;
if(sdpl) CARDLOCK();
size_t filesize = requiredfile.size();
if(sdpl) CARDUNLOCK();
size_t needread = filesize - index;
if (!needread) {
if(sdpl) { CARDLOCK(); requiredfile.close(); CARDUNLOCK(); }
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);
if(sdpl) CARDLOCK();
requiredfile.seek(index, SeekSet);
//vTaskDelay(1);
requiredfile.read(buffer, canread);
index += canread;
if (requiredfile) requiredfile.close();
if(sdpl) CARDUNLOCK();
return canread;
}
@@ -202,9 +190,7 @@ void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest
response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback, processor);
else
response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback);
//xSemaphoreTake(player.playmutex, portMAX_DELAY);
request->send(response);
//xSemaphoreGive(player.playmutex);
}
#ifndef DSP_NOT_FLIPPED
@@ -360,61 +346,61 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
if (strcmp(cmd, "getactive") == 0 ) { requestOnChange(GETACTIVE, clientId); return; }
if (strcmp(cmd, "newmode") == 0 ) { newConfigMode = atoi(val); requestOnChange(CHANGEMODE, 0); return; }
if (strcmp(cmd, "smartstart") == 0) {
byte valb = atoi(val);
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();
return;
}
if (strcmp(cmd, "audioinfo") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.audioinfo = valb;
config.save();
display.putRequest(AUDIOINFO);
return;
}
if (strcmp(cmd, "vumeter") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.vumeter = valb;
config.save();
display.putRequest(SHOWVUMETER);
return;
}
if (strcmp(cmd, "softap") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.softapdelay = valb;
config.save();
return;
}
if (strcmp(cmd, "invertdisplay") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.invertdisplay = valb;
config.save();
display.invert();
return;
}
if (strcmp(cmd, "numplaylist") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.numplaylist = valb;
config.save();
display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER);
return;
}
if (strcmp(cmd, "fliptouch") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.fliptouch = valb == 1;
config.save();
flipTS();
return;
}
if (strcmp(cmd, "dbgtouch") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.dbgtouch = valb == 1;
config.save();
return;
}
if (strcmp(cmd, "flipscreen") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.flipscreen = valb;
config.save();
display.flip();
@@ -422,19 +408,19 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
return;
}
if (strcmp(cmd, "brightness") == 0) {
byte valb = atoi(val);
uint8_t 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);
uint8_t valb = atoi(val);
config.setDspOn(valb == 1);
return;
}
if (strcmp(cmd, "contrast") == 0) {
byte valb = atoi(val);
uint8_t valb = atoi(val);
config.store.contrast = valb;
config.save();
display.setContrast();
@@ -574,7 +560,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
}
} /* EOF RESETS */
if (strcmp(cmd, "volume") == 0) {
byte v = atoi(val);
uint8_t v = atoi(val);
player.setVol(v);
}
if (strcmp(cmd, "sdpos") == 0) {
@@ -623,7 +609,6 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
return;
}
if (strcmp(cmd, "submitplaylist") == 0) {
// xSemaphoreTake(player.playmutex, portMAX_DELAY);
return;
}
if (strcmp(cmd, "submitplaylistdone") == 0) {
@@ -631,7 +616,6 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
//mqttPublishPlaylist();
mqttplaylistticker.attach(5, mqttplaylistSend);
#endif
// xSemaphoreGive(player.playmutex);
if (player.isRunning()) {
player.sendCommand({PR_PLAY, -config.store.lastStation});
}
@@ -649,7 +633,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
config.irchck = atoi(val);
}
if (strcmp(cmd, "irclr") == 0) {
byte cl = atoi(val);
uint8_t cl = atoi(val);
config.ircodes.irVals[config.irindex][cl] = 0;
}
#endif
@@ -737,7 +721,9 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index,
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);
config.clearCardStatus();
#ifdef USE_SD
sdman.clearCardStatus();
#endif
}
freeSpace = (float)SPIFFS.totalBytes()/100*68-SPIFFS.usedBytes();
request->_tempFile = SPIFFS.open(TMP_PATH , "w");

View File

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

View File

@@ -5,7 +5,7 @@
#include "config.h"
#include "telnet.h"
#include "display.h"
#include "sdmanager.h"
#include "netserver.h"
Player player;
@@ -13,9 +13,9 @@ QueueHandle_t playerQueue;
#if VS1053_CS!=255 && !I2S_INTERNAL
#if VS_HSPI
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ, HSPI, 13, 12, 14) {}
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ, &SPI2) {}
#else
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ) {}
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ, &SPI) {}
#endif
void ResetChip(){
pinMode(VS1053_RST, OUTPUT);
@@ -60,7 +60,6 @@ void Player::init() {
_status = STOPPED;
//setOutputPins(false);
_volTimer=false;
playmutex = xSemaphoreCreateMutex();
//randomSeed(analogRead(0));
#if PLAYER_FORCE_MONO
forceMono(true);
@@ -114,7 +113,7 @@ void Player::_stop(bool alreadyStopped){
void Player::initHeaders(const char *file) {
if(strlen(file)==0 || true) return; //TODO Read TAGs
connecttoFS(SD,file);
connecttoFS(sdman,file);
eofHeader = false;
while(!eofHeader) Audio::loop();
//netserver.requestOnChange(SDPOS, 0);
@@ -146,16 +145,14 @@ void Player::loop() {
}
#ifdef USE_SD
case PR_CHECKSD: {
config.checkSD();
sdman.checkSD();
break;
}
#endif
default: break;
}
}
xSemaphoreTake(playmutex, portMAX_DELAY);
Audio::loop();
xSemaphoreGive(playmutex);
if(!isRunning() && _status==PLAYING) _stop(true);
if(_volTimer){
if((millis()-_volTicks)>3000){
@@ -199,7 +196,7 @@ void Player::_play(uint16_t stationId) {
config.setSmartStart(0);
bool isConnected = false;
if(config.getMode()==PM_SDCARD && SDC_CS!=255)
isConnected=connecttoFS(SD,config.station.url,config.sdResumePos==0?_resumeFilePos:config.sdResumePos-player.sd_min);
isConnected=connecttoFS(sdman,config.station.url,config.sdResumePos==0?_resumeFilePos:config.sdResumePos-player.sd_min);
else {
config.store.play_mode=PM_WEB;
config.save();

View File

@@ -40,7 +40,6 @@ class Player: public Audio {
void _play(uint16_t stationId);
void _loadVol(uint8_t volume);
public:
SemaphoreHandle_t playmutex=NULL;
bool lockOutput = true;
bool resumeAfterUrl = false;
uint32_t sd_min, sd_max;

View File

@@ -0,0 +1,143 @@
#if SDC_CS!=255
#define USE_SD
#include "sdmanager.h"
#include "display.h"
#if defined(SD_SPIPINS) || SD_HSPI
SPIClass SDSPI(HSPI);
#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
return ready;
}
bool SDManager::cardPresent() {
if(sectorSize()<1) {
return false;
}
uint8_t buff[sectorSize()] = { 0 };
bool bread = readRAW(buff, 1);
if(sectorSize()>0 && !bread) end();
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);
strlcat(nomedia, "/.nomedia", BUFLEN);
bool nm = exists(nomedia);
return nm;
}
bool SDManager::_endsWith (const char* base, const char* str) {
int slen = strlen(str) - 1;
const char *p = base + strlen(base) - 1;
while(p > base && isspace(*p)) p--;
p -= slen;
if (p < base) return false;
return (strncmp(p, str, slen) == 0);
}
void SDManager::listSD(File &plSDfile, File &plSDindex, const char * dirname, uint8_t levels){
File root = sdman.open(dirname);
if(!root){
Serial.println("##[ERROR]#\tFailed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("##[ERROR]#\tNot a directory");
return;
}
File file = root.openNextFile();
uint32_t pos = 0;
while(file){
vTaskDelay(2);
bool fid = file.isDirectory();
const char * fp = file.path();
const char * fn = file.name();
if(fid){
if(levels && !_checkNoMedia(fp)){
listSD(plSDfile, plSDindex, fp, levels -1);
}
} else {
if(_endsWith(strlwr((char*)fn), ".mp3") || _endsWith(fn, ".m4a") || _endsWith(fn, ".aac") || _endsWith(fn, ".wav") || _endsWith(fn, ".flac")){
pos = plSDfile.position();
plSDfile.print(fn); plSDfile.print("\t"); plSDfile.print(fp); plSDfile.print("\t"); plSDfile.println(0);
plSDindex.write((uint8_t *) &pos, 4);
Serial.print(".");
if(display.mode()==SDCHANGE) display.putRequest(SDFILEINDEX, _sdFCount+1);
_sdFCount++;
if(_sdFCount%64==0) Serial.println();
}
}
if(file) file.close(); file = root.openNextFile();
}
if(root) root.close();
}
void SDManager::indexSDPlaylist() {
_sdFCount = 0;
if(exists(PLAYLIST_SD_PATH)) remove(PLAYLIST_SD_PATH);
if(exists(INDEX_SD_PATH)) remove(INDEX_SD_PATH);
File playlist = open(PLAYLIST_SD_PATH, "w", true);
if (!playlist) {
return;
}
File index = open(INDEX_SD_PATH, "w", true);
listSD(playlist, index, "/", SD_MAX_LEVELS);
index.flush();
index.close();
playlist.flush();
playlist.close();
Serial.println();
delay(50);
}
#endif

View File

@@ -0,0 +1,39 @@
#ifndef sdmanager_h
#define sdmanager_h
#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
#include "vfs_api.h"
#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 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);
};
extern SDManager sdman;
#if defined(SD_SPIPINS) || SD_HSPI
extern SPIClass SDSPI;
#endif
#endif

View File

@@ -1,45 +0,0 @@
#include "spidog.h"
SPIDog sdog;
SPIDog::SPIDog() {
_busy = false;
}
bool SPIDog::begin(){
if(_spiMutex==NULL){
_spiMutex = xSemaphoreCreateMutex();
if(_spiMutex==NULL) return false;
}
return true;
}
bool SPIDog::takeMutex(){
if(_spiMutex == NULL) {
return false;
}
do { } while (xSemaphoreTake(_spiMutex, portMAX_DELAY) != pdPASS);
_busy = true;
return true;
}
void SPIDog::giveMutex(){
if(_spiMutex != NULL) xSemaphoreGive(_spiMutex);
_busy = false;
}
bool SPIDog::canTake(){
if(_spiMutex == NULL) {
return false;
}
return xSemaphoreTake(_spiMutex, 0) == pdPASS;
}
bool SPIDog::breakMutex(uint8_t ticks){
if(!_busy){
giveMutex();
vTaskDelay(ticks);
return takeMutex();
}
return false;
}

View File

@@ -1,29 +0,0 @@
#ifndef spidog_h
#define spidog_h
#include <Arduino.h>
#include "options.h"
#ifndef SDOG_PORT_DELAY
#define SDOG_PORT_DELAY portMAX_DELAY
#endif
class SPIDog {
private:
SemaphoreHandle_t _spiMutex=NULL;
bool _busy;
public:
SPIDog();
~SPIDog(){}
bool begin();
bool takeMutex();
void giveMutex();
bool canTake();
bool breakMutex(uint8_t ticks=5);
bool busy() { return _busy; }
bool tm() { return takeMutex(); }
void gm() { giveMutex(); }
};
extern SPIDog sdog;
#endif

View File

@@ -119,7 +119,7 @@ void Telnet::print(const char *buf) {
Serial.print(buf);
}
void Telnet::print(byte id, const char *buf) {
void Telnet::print(uint8_t id, const char *buf) {
if (clients[id] && clients[id].connected()) {
clients[id].print(buf);
}
@@ -143,7 +143,7 @@ void Telnet::printf(const char *format, ...) {
Serial.print(buf);
}
void Telnet::printf(byte id, const char *format, ...) {
void Telnet::printf(uint8_t id, const char *format, ...) {
char buf[MAX_PRINTF_LEN];
va_list argptr;
va_start(argptr, format);
@@ -158,7 +158,7 @@ void Telnet::printf(byte id, const char *format, ...) {
}
}
void Telnet::on_connect(const char* str, byte clientId) {
void Telnet::on_connect(const char* str, uint8_t clientId) {
Serial.printf("Telnet: [%d] %s connected\n", clientId, str);
print(clientId, "\nWelcome to ёRadio!\n(Use ^] + q to disconnect.)\n> ");
}
@@ -181,7 +181,7 @@ void Telnet::info() {
telnet.printf("> ");
}
void Telnet::on_input(const char* str, byte clientId) {
void Telnet::on_input(const char* str, uint8_t clientId) {
if (strlen(str) == 0) return;
if(network.status == CONNECTED){
if (strcmp(str, "cli.prev") == 0 || strcmp(str, "prev") == 0) {
@@ -245,7 +245,7 @@ void Telnet::on_input(const char* str, byte 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 = (byte)sstart;
config.store.smartstart = (uint8_t)sstart;
printf(clientId, "new smartstart value is: %d\n> ", config.store.smartstart);
config.save();
return;
@@ -258,7 +258,7 @@ void Telnet::on_input(const char* str, byte clientId) {
}
char sName[BUFLEN], sUrl[BUFLEN];
int sOvol;
byte c = 1;
uint8_t c = 1;
while (file.available()) {
if (config.parseCSV(file.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) {
printf(clientId, "#CLI.LISTNUM#: %*d: %s, %s\n", 3, c, sName, sUrl);
@@ -394,7 +394,7 @@ void Telnet::on_input(const char* str, byte clientId) {
File file = SPIFFS.open(SSIDS_PATH, "r");
if (file && !file.isDirectory()) {
char sSid[BUFLEN], sPas[BUFLEN];
byte c = 1;
uint8_t c = 1;
while (file.available()) {
if (config.parseSsid(file.readStringUntil('\n').c_str(), sSid, sPas)) {
printf(clientId, "%d: %s, %s\n", c, sSid, sPas);
@@ -410,7 +410,7 @@ void Telnet::on_input(const char* str, byte clientId) {
File file = SPIFFS.open(SSIDS_PATH, "r");
if (file && !file.isDirectory()) {
char sSid[BUFLEN], sPas[BUFLEN];
byte c = 1;
uint8_t c = 1;
while (file.available()) {
if (config.parseSsid(file.readStringUntil('\n').c_str(), sSid, sPas)) {
if(c==config.store.lastSSID) printf(clientId, "%d: %s, %s\n", c, sSid, sPas);

View File

@@ -12,9 +12,9 @@ class Telnet {
bool begin(bool quiet=false);
void loop();
void stop();
void print(byte id, const char *buf);
void print(uint8_t id, const char *buf);
void print(const char *buf);
void printf(byte id, const char *format, ...);
void printf(uint8_t id, const char *format, ...);
void printf(const char *format, ...);
void cleanupClients();
void info();
@@ -22,8 +22,8 @@ class Telnet {
WiFiServer server = WiFiServer(23);
WiFiClient clients[MAX_TLN_CLIENTS];
void emptyClientStream(WiFiClient client);
void on_connect(const char* str, byte clientId);
void on_input(const char* str, byte clientId);
void on_connect(const char* str, uint8_t clientId);
void on_input(const char* str, uint8_t clientId);
private:
bool _isIPSet(IPAddress ip);
void handleSerial();