v0.8.00b
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_GC9106
|
||||
|
||||
#include "Adafruit_GC9106Ex.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ILI9225
|
||||
#include "TFT_22_ILI9225Fix.h"
|
||||
|
||||
|
||||
@@ -220,12 +220,10 @@ class TFT_22_ILI9225 {
|
||||
/// @return horizontal size of the screen, in pixels
|
||||
/// @note 240 means 240 pixels and thus 0..239 coordinates (decimal)
|
||||
uint16_t maxX(void);
|
||||
|
||||
/// Screen size, y-axis
|
||||
/// @return vertical size of the screen, in pixels
|
||||
/// @note 220 means 220 pixels and thus 0..219 coordinates (decimal)
|
||||
uint16_t maxY(void);
|
||||
|
||||
/// Draw circle
|
||||
/// @param x0 center, point coordinate, x-axis
|
||||
/// @param y0 center, point coordinate, y-axis
|
||||
@@ -333,7 +331,7 @@ class TFT_22_ILI9225 {
|
||||
/// @param ch ASCII character
|
||||
/// @param color 16-bit color, default=white
|
||||
/// @return width of character in display pixels
|
||||
uint16_t drawChar(uint16_t x, uint16_t y, uint16_t ch, uint16_t color = COLOR_WHITE);
|
||||
virtual uint16_t drawChar(uint16_t x, uint16_t y, uint16_t ch, uint16_t color = COLOR_WHITE);
|
||||
|
||||
/// width of an ASCII character (pixel )
|
||||
/// @param ch ASCII character
|
||||
@@ -400,8 +398,8 @@ class TFT_22_ILI9225 {
|
||||
/// @return width of character in display pixels
|
||||
uint16_t drawGFXChar(int16_t x, int16_t y, unsigned char c, uint16_t color);
|
||||
|
||||
void startWrite(void);
|
||||
void endWrite(void);
|
||||
virtual void startWrite(void);
|
||||
virtual void endWrite(void);
|
||||
|
||||
private:
|
||||
|
||||
@@ -458,7 +456,7 @@ class TFT_22_ILI9225 {
|
||||
|
||||
bool hwSPI, blState;
|
||||
|
||||
_currentFont cfont;
|
||||
//_currentFont cfont;
|
||||
|
||||
#ifdef ESP32
|
||||
SPIClass _spi;
|
||||
@@ -471,6 +469,8 @@ class TFT_22_ILI9225 {
|
||||
void getGFXCharExtent(uint8_t c, int16_t *gw, int16_t *gh, int16_t *xa);
|
||||
|
||||
GFXfont *gfxFont;
|
||||
|
||||
_currentFont cfont;
|
||||
};
|
||||
|
||||
class GFXcanvas16 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Based on the work by DFRobot
|
||||
// Based on the LiquidCrystal_I2C library https://github.com/johnrickman/LiquidCrystal_I2C
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_1602I2C || DSP_MODEL==DSP_2004I2C
|
||||
|
||||
#include "LiquidCrystalI2CEx.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if VS1053_CS==255
|
||||
/*
|
||||
* Audio.cpp
|
||||
@@ -3892,26 +3892,32 @@ bool Audio::parseContentType(char* ct) {
|
||||
case CT_MP3:
|
||||
m_codec = CODEC_MP3;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is mp3", ct); } //ok is likely mp3
|
||||
if(audio_info) audio_info("format is mp3");
|
||||
break;
|
||||
case CT_AAC:
|
||||
m_codec = CODEC_AAC;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is aac", ct); }
|
||||
if(audio_info) audio_info("format is aac");
|
||||
break;
|
||||
case CT_M4A:
|
||||
m_codec = CODEC_M4A;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is aac", ct); }
|
||||
if(audio_info) audio_info("format is aac");
|
||||
break;
|
||||
case CT_FLAC:
|
||||
m_codec = CODEC_FLAC;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is flac", ct); }
|
||||
if(audio_info) audio_info("format is flac");
|
||||
break;
|
||||
case CT_WAV:
|
||||
m_codec = CODEC_WAV;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is wav", ct); }
|
||||
if(audio_info) audio_info("format is wav");
|
||||
break;
|
||||
case CT_OGG:
|
||||
m_codec = CODEC_OGG;
|
||||
if(m_f_Log) { log_i("ContentType %s found", ct); }
|
||||
if(audio_info) audio_info("format is ogg");
|
||||
break;
|
||||
|
||||
case CT_PLS:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if I2S_DOUT==255
|
||||
/*
|
||||
* vs1053_ext.cpp
|
||||
@@ -1501,26 +1501,32 @@ bool Audio::parseContentType(char* ct) {
|
||||
case CT_MP3:
|
||||
m_codec = CODEC_MP3;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is mp3", ct); } //ok is likely mp3
|
||||
if(audio_info) audio_info("format is mp3");
|
||||
break;
|
||||
case CT_AAC:
|
||||
m_codec = CODEC_AAC;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is aac", ct); }
|
||||
if(audio_info) audio_info("format is aac");
|
||||
break;
|
||||
case CT_M4A:
|
||||
m_codec = CODEC_M4A;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is aac", ct); }
|
||||
if(audio_info) audio_info("format is aac");
|
||||
break;
|
||||
case CT_FLAC:
|
||||
m_codec = CODEC_FLAC;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is flac", ct); }
|
||||
if(audio_info) audio_info("format is flac");
|
||||
break;
|
||||
case CT_WAV:
|
||||
m_codec = CODEC_WAV;
|
||||
if(m_f_Log) { log_i("ContentType %s, format is wav", ct); }
|
||||
if(audio_info) audio_info("format is wav");
|
||||
break;
|
||||
case CT_OGG:
|
||||
m_codec = CODEC_OGG;
|
||||
if(m_f_Log) { log_i("ContentType %s found", ct); }
|
||||
if(audio_info) audio_info("format is ogg");
|
||||
break;
|
||||
|
||||
case CT_PLS:
|
||||
|
||||
534
yoRadio/src/core/config.cpp
Normal file
534
yoRadio/src/core/config.cpp
Normal file
@@ -0,0 +1,534 @@
|
||||
#include "config.h"
|
||||
#include <EEPROM.h>
|
||||
#include <SPIFFS.h>
|
||||
#include "display.h"
|
||||
#include "player.h"
|
||||
|
||||
Config config;
|
||||
|
||||
void u8fix(char *src){
|
||||
char last = src[strlen(src)-1];
|
||||
if ((uint8_t)last >= 0xC2) src[strlen(src)-1]='\0';
|
||||
}
|
||||
|
||||
void Config::init() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
#if IR_PIN!=255
|
||||
irindex=-1;
|
||||
#endif
|
||||
eepromRead(EEPROM_START, store);
|
||||
if (store.config_set != 4262) setDefaults();
|
||||
//if (!SPIFFS.begin(false, "/spiffs", 30)) {
|
||||
if (!SPIFFS.begin(false)) {
|
||||
return;
|
||||
}
|
||||
loadTheme();
|
||||
ssidsCount = 0;
|
||||
initPlaylist();
|
||||
if (store.lastStation == 0 && store.countStation > 0) {
|
||||
store.lastStation = 1;
|
||||
save();
|
||||
}
|
||||
loadStation(store.lastStation);
|
||||
#if IR_PIN!=255
|
||||
eepromRead(EEPROM_START_IR, ircodes);
|
||||
if(ircodes.ir_set!=4224){
|
||||
ircodes.ir_set=4224;
|
||||
memset(ircodes.irVals, 0, sizeof(ircodes.irVals));
|
||||
}
|
||||
#endif
|
||||
#if BRIGHTNESS_PIN!=255
|
||||
pinMode(BRIGHTNESS_PIN, OUTPUT);
|
||||
setBrightness(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t Config::color565(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
}
|
||||
|
||||
void Config::loadTheme(){
|
||||
theme.background = color565(COLOR_BACKGROUND);
|
||||
theme.meta = color565(COLOR_STATION_NAME);
|
||||
theme.metabg = color565(COLOR_STATION_BG);
|
||||
theme.metafill = color565(COLOR_STATION_FILL);
|
||||
theme.title1 = color565(COLOR_SNG_TITLE_1);
|
||||
theme.title2 = color565(COLOR_SNG_TITLE_2);
|
||||
theme.digit = color565(COLOR_DIGITS);
|
||||
theme.div = color565(COLOR_DIVIDER);
|
||||
theme.weather = color565(COLOR_WEATHER);
|
||||
theme.vumax = color565(COLOR_VU_MAX);
|
||||
theme.vumin = color565(COLOR_VU_MIN);
|
||||
theme.clock = color565(COLOR_CLOCK);
|
||||
theme.seconds = color565(COLOR_SECONDS);
|
||||
theme.dow = color565(COLOR_DAY_OF_W);
|
||||
theme.date = color565(COLOR_DATE);
|
||||
theme.heap = color565(COLOR_HEAP);
|
||||
theme.buffer = color565(COLOR_BUFFER);
|
||||
theme.ip = color565(COLOR_IP);
|
||||
theme.vol = color565(COLOR_VOLUME_VALUE);
|
||||
theme.rssi = color565(COLOR_RSSI);
|
||||
theme.bitrate = color565(COLOR_BITRATE);
|
||||
theme.volbarout = color565(COLOR_VOLBAR_OUT);
|
||||
theme.volbarin = color565(COLOR_VOLBAR_IN);
|
||||
theme.playlist[0] = color565(COLOR_PLAYLIST_0);
|
||||
theme.playlist[1] = color565(COLOR_PLAYLIST_1);
|
||||
theme.playlist[2] = color565(COLOR_PLAYLIST_2);
|
||||
theme.playlist[3] = color565(COLOR_PLAYLIST_3);
|
||||
theme.playlist[4] = color565(COLOR_PLAYLIST_4);
|
||||
}
|
||||
|
||||
template <class T> int Config::eepromWrite(int ee, const T& value) {
|
||||
const byte* p = (const byte*)(const void*)&value;
|
||||
int i;
|
||||
for (i = 0; i < sizeof(value); i++)
|
||||
EEPROM.write(ee++, *p++);
|
||||
EEPROM.commit();
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class T> int Config::eepromRead(int ee, T& value) {
|
||||
byte* p = (byte*)(void*)&value;
|
||||
int i;;
|
||||
for (i = 0; i < sizeof(value); i++)
|
||||
*p++ = EEPROM.read(ee++);
|
||||
return i;
|
||||
}
|
||||
|
||||
void Config::setDefaults() {
|
||||
store.config_set = 4262;
|
||||
store.volume = 12;
|
||||
store.balance = 0;
|
||||
store.trebble = 0;
|
||||
store.middle = 0;
|
||||
store.bass = 0;
|
||||
store.lastStation = 0;
|
||||
store.countStation = 0;
|
||||
store.lastSSID = 0;
|
||||
store.audioinfo = false;
|
||||
store.smartstart = 2;
|
||||
store.tzHour = 3;
|
||||
store.tzMin = 0;
|
||||
store.timezoneOffset = 0;
|
||||
|
||||
store.vumeter=false;
|
||||
store.softapdelay=0;
|
||||
store.flipscreen=false;
|
||||
store.invertdisplay=false;
|
||||
store.numplaylist=false;
|
||||
store.fliptouch=false;
|
||||
store.dbgtouch=false;
|
||||
store.dspon=true;
|
||||
store.brightness=100;
|
||||
store.contrast=55;
|
||||
strlcpy(store.sntp1,"pool.ntp.org", 35);
|
||||
strlcpy(store.sntp2,"1.ru.pool.ntp.org", 35);
|
||||
store.showweather=false;
|
||||
strlcpy(store.weatherlat,"55.7512", 10);
|
||||
strlcpy(store.weatherlon,"37.6184", 10);
|
||||
strlcpy(store.weatherkey,"", 64);
|
||||
store.volsteps = 1;
|
||||
store.encacc = 200;
|
||||
store.irto = 80;
|
||||
store.irtlp = 35;
|
||||
store.btnpullup = true;
|
||||
store.btnlongpress = 200;
|
||||
store.btnclickticks = 300;
|
||||
store.btnpressticks = 500;
|
||||
store.encpullup = false;
|
||||
store.enchalf = false;
|
||||
store.enc2pullup = false;
|
||||
store.enc2half = false;
|
||||
store.forcemono = false;
|
||||
store.i2sinternal = false;
|
||||
store.rotate90 = false;
|
||||
}
|
||||
|
||||
void Config::setTimezone(int8_t tzh, int8_t tzm) {
|
||||
store.tzHour = tzh;
|
||||
store.tzMin = tzm;
|
||||
save();
|
||||
}
|
||||
|
||||
void Config::setTimezoneOffset(uint16_t tzo) {
|
||||
store.timezoneOffset = tzo;
|
||||
save();
|
||||
}
|
||||
|
||||
uint16_t Config::getTimezoneOffset() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void Config::save() {
|
||||
eepromWrite(EEPROM_START, store);
|
||||
}
|
||||
|
||||
#if IR_PIN!=255
|
||||
void Config::saveIR(){
|
||||
eepromWrite(EEPROM_START_IR, ircodes);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Config::saveVolume(){
|
||||
EEPROM.write(EEPROM_START + sizeof(store.config_set), store.volume);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
byte Config::setVolume(byte val) {
|
||||
store.volume = val;
|
||||
return store.volume;
|
||||
}
|
||||
|
||||
void Config::setTone(int8_t bass, int8_t middle, int8_t trebble) {
|
||||
store.bass = bass;
|
||||
store.middle = middle;
|
||||
store.trebble = trebble;
|
||||
save();
|
||||
}
|
||||
|
||||
void Config::setSmartStart(byte ss) {
|
||||
if (store.smartstart < 2) {
|
||||
store.smartstart = ss;
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
void Config::setBalance(int8_t balance) {
|
||||
store.balance = balance;
|
||||
save();
|
||||
}
|
||||
|
||||
byte Config::setLastStation(byte val) {
|
||||
store.lastStation = val;
|
||||
save();
|
||||
return store.lastStation;
|
||||
}
|
||||
|
||||
byte Config::setCountStation(byte val) {
|
||||
store.countStation = val;
|
||||
save();
|
||||
return store.countStation;
|
||||
}
|
||||
|
||||
byte Config::setLastSSID(byte val) {
|
||||
store.lastSSID = val;
|
||||
save();
|
||||
return store.lastSSID;
|
||||
}
|
||||
|
||||
void Config::setTitle(const char* title) {
|
||||
memset(config.station.title, 0, BUFLEN);
|
||||
strlcpy(config.station.title, title, BUFLEN);
|
||||
u8fix(config.station.title);
|
||||
display.putRequest(NEWTITLE);
|
||||
}
|
||||
|
||||
void Config::setStation(const char* station) {
|
||||
memset(config.station.name, 0, BUFLEN);
|
||||
strlcpy(config.station.name, station, BUFLEN);
|
||||
u8fix(config.station.title);
|
||||
}
|
||||
|
||||
void Config::indexPlaylist() {
|
||||
File playlist = SPIFFS.open(PLAYLIST_PATH, "r");
|
||||
if (!playlist) {
|
||||
return;
|
||||
}
|
||||
char sName[BUFLEN], sUrl[BUFLEN];
|
||||
int sOvol;
|
||||
File index = SPIFFS.open(INDEX_PATH, "w");
|
||||
while (playlist.available()) {
|
||||
uint32_t pos = playlist.position();
|
||||
if (parseCSV(playlist.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) {
|
||||
index.write((byte *) &pos, 4);
|
||||
}
|
||||
}
|
||||
index.close();
|
||||
playlist.close();
|
||||
}
|
||||
|
||||
void Config::initPlaylist() {
|
||||
store.countStation = 0;
|
||||
if (!SPIFFS.exists(INDEX_PATH)) indexPlaylist();
|
||||
|
||||
if (SPIFFS.exists(INDEX_PATH)) {
|
||||
File index = SPIFFS.open(INDEX_PATH, "r");
|
||||
store.countStation = index.size() / 4;
|
||||
index.close();
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
void Config::loadStation(uint16_t ls) {
|
||||
char sName[BUFLEN], sUrl[BUFLEN];
|
||||
int sOvol;
|
||||
if (store.countStation == 0) {
|
||||
memset(station.url, 0, BUFLEN);
|
||||
memset(station.name, 0, BUFLEN);
|
||||
strncpy(station.name, "ёRadio", BUFLEN);
|
||||
station.ovol = 0;
|
||||
return;
|
||||
}
|
||||
if (ls > store.countStation) {
|
||||
ls = 1;
|
||||
}
|
||||
File playlist = SPIFFS.open(PLAYLIST_PATH, "r");
|
||||
|
||||
File index = SPIFFS.open(INDEX_PATH, "r");
|
||||
index.seek((ls - 1) * 4, SeekSet);
|
||||
uint32_t pos;
|
||||
|
||||
index.readBytes((char *) &pos, 4);
|
||||
|
||||
index.close();
|
||||
playlist.seek(pos, SeekSet);
|
||||
if (parseCSV(playlist.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) {
|
||||
memset(station.url, 0, BUFLEN);
|
||||
memset(station.name, 0, BUFLEN);
|
||||
strncpy(station.name, sName, BUFLEN);
|
||||
strncpy(station.url, sUrl, BUFLEN);
|
||||
station.ovol = sOvol;
|
||||
setLastStation(ls);
|
||||
}
|
||||
playlist.close();
|
||||
}
|
||||
|
||||
void Config::fillPlMenu(char plmenu[][40], int from, byte count, bool removeNum) {
|
||||
int ls = from;
|
||||
byte c = 0;
|
||||
bool finded = false;
|
||||
char sName[BUFLEN], sUrl[BUFLEN];
|
||||
int sOvol;
|
||||
if (store.countStation == 0) {
|
||||
return;
|
||||
}
|
||||
File playlist = SPIFFS.open(PLAYLIST_PATH, "r");
|
||||
File index = SPIFFS.open(INDEX_PATH, "r");
|
||||
while (true) {
|
||||
if (ls < 1) {
|
||||
ls++;
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
if (!finded) {
|
||||
index.seek((ls - 1) * 4, SeekSet);
|
||||
uint32_t pos;
|
||||
index.readBytes((char *) &pos, 4);
|
||||
finded = true;
|
||||
index.close();
|
||||
playlist.seek(pos, SeekSet);
|
||||
}
|
||||
while (playlist.available()) {
|
||||
if (parseCSV(playlist.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) {
|
||||
if(config.store.numplaylist){
|
||||
if(removeNum){
|
||||
strlcpy(plmenu[c], sName, 39);
|
||||
}else{
|
||||
char buf[BUFLEN+10];
|
||||
sprintf(buf, "%d %s", (int)(from+c), sName);
|
||||
strlcpy(plmenu[c], buf, 39);
|
||||
}
|
||||
}else{
|
||||
strlcpy(plmenu[c], sName, 39);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
if (c >= count) break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
playlist.close();
|
||||
}
|
||||
|
||||
bool Config::parseCSV(const char* line, char* name, char* url, int &ovol) {
|
||||
char *tmpe;
|
||||
const char* cursor = line;
|
||||
char buf[5];
|
||||
tmpe = strstr(cursor, "\t");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(name, cursor, tmpe - cursor + 1);
|
||||
if (strlen(name) == 0) return false;
|
||||
cursor = tmpe + 1;
|
||||
tmpe = strstr(cursor, "\t");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(url, cursor, tmpe - cursor + 1);
|
||||
if (strlen(url) == 0) return false;
|
||||
cursor = tmpe + 1;
|
||||
if (strlen(cursor) == 0) return false;
|
||||
strlcpy(buf, cursor, 4);
|
||||
ovol = atoi(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Config::parseJSON(const char* line, char* name, char* url, int &ovol) {
|
||||
char* tmps, *tmpe;
|
||||
const char* cursor = line;
|
||||
char port[8], host[246], file[254];
|
||||
tmps = strstr(cursor, "\":\"");
|
||||
if (tmps == NULL) return false;
|
||||
tmpe = strstr(tmps, "\",\"");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(name, tmps + 3, tmpe - tmps - 3 + 1);
|
||||
if (strlen(name) == 0) return false;
|
||||
cursor = tmpe + 3;
|
||||
tmps = strstr(cursor, "\":\"");
|
||||
if (tmps == NULL) return false;
|
||||
tmpe = strstr(tmps, "\",\"");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(host, tmps + 3, tmpe - tmps - 3 + 1);
|
||||
if (strlen(host) == 0) return false;
|
||||
if (strstr(host, "http://") == NULL && strstr(host, "https://") == NULL) {
|
||||
sprintf(file, "http://%s", host);
|
||||
strlcpy(host, file, strlen(file) + 1);
|
||||
}
|
||||
cursor = tmpe + 3;
|
||||
tmps = strstr(cursor, "\":\"");
|
||||
if (tmps == NULL) return false;
|
||||
tmpe = strstr(tmps, "\",\"");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(file, tmps + 3, tmpe - tmps - 3 + 1);
|
||||
cursor = tmpe + 3;
|
||||
tmps = strstr(cursor, "\":\"");
|
||||
if (tmps == NULL) return false;
|
||||
tmpe = strstr(tmps, "\",\"");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(port, tmps + 3, tmpe - tmps - 3 + 1);
|
||||
int p = atoi(port);
|
||||
if (p > 0) {
|
||||
sprintf(url, "%s:%d%s", host, p, file);
|
||||
} else {
|
||||
sprintf(url, "%s%s", host, file);
|
||||
}
|
||||
cursor = tmpe + 3;
|
||||
tmps = strstr(cursor, "\":\"");
|
||||
if (tmps == NULL) return false;
|
||||
tmpe = strstr(tmps, "\"}");
|
||||
if (tmpe == NULL) return false;
|
||||
strlcpy(port, tmps + 3, tmpe - tmps - 3 + 1);
|
||||
ovol = atoi(port);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Config::parseWsCommand(const char* line, char* cmd, char* val, byte cSize) {
|
||||
char *tmpe;
|
||||
tmpe = strstr(line, "=");
|
||||
if (tmpe == NULL) return false;
|
||||
memset(cmd, 0, cSize);
|
||||
strlcpy(cmd, line, tmpe - line + 1);
|
||||
if (strlen(tmpe + 1) == 0) return false;
|
||||
memset(val, 0, cSize);
|
||||
strlcpy(val, tmpe + 1, strlen(line) - strlen(cmd) + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Config::parseSsid(const char* line, char* ssid, char* pass) {
|
||||
char *tmpe;
|
||||
tmpe = strstr(line, "\t");
|
||||
if (tmpe == NULL) return false;
|
||||
uint16_t pos = tmpe - line;
|
||||
if (pos > 19 || strlen(line) > 61) return false;
|
||||
memset(ssid, 0, 20);
|
||||
strlcpy(ssid, line, pos + 1);
|
||||
memset(pass, 0, 40);
|
||||
strlcpy(pass, line + pos + 1, strlen(line) - pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Config::saveWifiFromNextion(const char* post){
|
||||
File file = SPIFFS.open(SSIDS_PATH, "w");
|
||||
if (!file) {
|
||||
return false;
|
||||
} else {
|
||||
file.print(post);
|
||||
file.close();
|
||||
ESP.restart();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
char ssidval[20], passval[40];
|
||||
byte c = 0;
|
||||
while (file.available()) {
|
||||
if (parseSsid(file.readStringUntil('\n').c_str(), ssidval, passval)) {
|
||||
strlcpy(ssids[c].ssid, ssidval, 20);
|
||||
strlcpy(ssids[c].password, passval, 40);
|
||||
ssidsCount++;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Config::setBrightness(bool dosave){
|
||||
#if BRIGHTNESS_PIN!=255
|
||||
if(!store.dspon && dosave) {
|
||||
display.wakeup();
|
||||
}
|
||||
//analogWrite(BRIGHTNESS_PIN, config.store.dspon?map(store.brightness, 0, 100, 0, 255):0);
|
||||
analogWrite(BRIGHTNESS_PIN, map(store.brightness, 0, 100, 0, 255));
|
||||
if(!store.dspon) store.dspon = true;
|
||||
if(dosave) save();
|
||||
#endif
|
||||
#ifdef USE_NEXTION
|
||||
// if(!store.dspon && dosave) {
|
||||
nextion.wake();
|
||||
// }
|
||||
char cmd[15];
|
||||
snprintf(cmd, 15, "dims=%d", store.brightness);
|
||||
nextion.putcmd(cmd);
|
||||
if(!store.dspon) store.dspon = true;
|
||||
if(dosave) save();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Config::setDspOn(bool dspon){
|
||||
store.dspon = dspon;
|
||||
save();
|
||||
#ifdef USE_NEXTION
|
||||
if(!dspon) nextion.sleep();
|
||||
else nextion.wake();
|
||||
#endif
|
||||
if(!dspon){
|
||||
#if BRIGHTNESS_PIN!=255
|
||||
analogWrite(BRIGHTNESS_PIN, 0);
|
||||
#endif
|
||||
display.deepsleep();
|
||||
}else{
|
||||
display.wakeup();
|
||||
#if BRIGHTNESS_PIN!=255
|
||||
analogWrite(BRIGHTNESS_PIN, map(store.brightness, 0, 100, 0, 255));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Config::doSleep(){
|
||||
if(BRIGHTNESS_PIN!=255) analogWrite(BRIGHTNESS_PIN, 0);
|
||||
display.deepsleep();
|
||||
#ifdef USE_NEXTION
|
||||
nextion.sleep();
|
||||
#endif
|
||||
if(WAKE_PIN!=255) esp_sleep_enable_ext0_wakeup((gpio_num_t)WAKE_PIN, LOW);
|
||||
esp_sleep_enable_timer_wakeup(config.sleepfor * 60 * 1000000ULL);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
void Config::sleepForAfter(uint16_t sf, uint16_t sa){
|
||||
sleepfor = sf;
|
||||
if(sa > 0) _sleepTimer.attach(sa * 60, doSleep);
|
||||
else doSleep();
|
||||
}
|
||||
185
yoRadio/src/core/config.h
Normal file
185
yoRadio/src/core/config.h
Normal file
@@ -0,0 +1,185 @@
|
||||
#ifndef config_h
|
||||
#define config_h
|
||||
#include "Arduino.h"
|
||||
#include <Ticker.h>
|
||||
#include "options.h"
|
||||
|
||||
#define EEPROM_SIZE 768
|
||||
#define EEPROM_START 500
|
||||
#define EEPROM_START_IR 0
|
||||
#define EEPROM_START_2 10
|
||||
#define BUFLEN 140
|
||||
#define PLAYLIST_PATH "/data/playlist.csv"
|
||||
#define SSIDS_PATH "/data/wifi.csv"
|
||||
#define TMP_PATH "/data/tmpfile.txt"
|
||||
#define INDEX_PATH "/data/index.dat"
|
||||
|
||||
#ifdef DEBUG_V
|
||||
#define DBGH() { Serial.printf("[%s:%s:%d] Heap: %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__, xPortGetFreeHeapSize()); }
|
||||
#define DBGVB( ... ) { char buf[200]; sprintf( buf, __VA_ARGS__ ) ; Serial.print("[DEBUG]\t"); Serial.println(buf); }
|
||||
#else
|
||||
#define DBGVB( ... )
|
||||
#define DBGH()
|
||||
#endif
|
||||
#define EVERY_MS(x) static uint32_t tmr; bool flag = millis() - tmr >= (x); if (flag) tmr += (x); if (flag)
|
||||
void u8fix(char *src);
|
||||
|
||||
struct theme_t {
|
||||
uint16_t background;
|
||||
uint16_t meta;
|
||||
uint16_t metabg;
|
||||
uint16_t metafill;
|
||||
uint16_t title1;
|
||||
uint16_t title2;
|
||||
uint16_t digit;
|
||||
uint16_t div;
|
||||
uint16_t weather;
|
||||
uint16_t vumax;
|
||||
uint16_t vumin;
|
||||
uint16_t clock;
|
||||
uint16_t seconds;
|
||||
uint16_t dow;
|
||||
uint16_t date;
|
||||
uint16_t heap;
|
||||
uint16_t buffer;
|
||||
uint16_t ip;
|
||||
uint16_t vol;
|
||||
uint16_t rssi;
|
||||
uint16_t bitrate;
|
||||
uint16_t volbarout;
|
||||
uint16_t volbarin;
|
||||
uint16_t playlist[5];
|
||||
};
|
||||
struct config_t
|
||||
{
|
||||
unsigned int config_set; //must be 4262
|
||||
byte volume;
|
||||
int8_t balance;
|
||||
int8_t trebble;
|
||||
int8_t middle;
|
||||
int8_t bass;
|
||||
uint16_t lastStation;
|
||||
uint16_t countStation;
|
||||
byte lastSSID;
|
||||
bool audioinfo;
|
||||
byte smartstart;
|
||||
int8_t tzHour;
|
||||
int8_t tzMin;
|
||||
uint16_t timezoneOffset;
|
||||
|
||||
bool vumeter;
|
||||
uint8_t softapdelay;
|
||||
bool flipscreen;
|
||||
bool invertdisplay;
|
||||
bool numplaylist;
|
||||
bool fliptouch;
|
||||
bool dbgtouch;
|
||||
bool dspon;
|
||||
uint8_t brightness;
|
||||
uint8_t contrast;
|
||||
char sntp1[35];
|
||||
char sntp2[35];
|
||||
bool showweather;
|
||||
char weatherlat[10];
|
||||
char weatherlon[10];
|
||||
char weatherkey[64];
|
||||
uint8_t volsteps;
|
||||
uint16_t encacc;
|
||||
uint8_t irto;
|
||||
uint8_t irtlp;
|
||||
bool btnpullup;
|
||||
uint16_t btnlongpress;
|
||||
uint16_t btnclickticks;
|
||||
uint16_t btnpressticks;
|
||||
bool encpullup;
|
||||
bool enchalf;
|
||||
bool enc2pullup;
|
||||
bool enc2half;
|
||||
bool forcemono;
|
||||
bool i2sinternal;
|
||||
bool rotate90;
|
||||
};
|
||||
|
||||
#if IR_PIN!=255
|
||||
struct ircodes_t
|
||||
{
|
||||
unsigned int ir_set; //must be 4224
|
||||
uint64_t irVals[20][3];
|
||||
};
|
||||
#endif
|
||||
|
||||
struct station_t
|
||||
{
|
||||
char name[BUFLEN];
|
||||
char url[BUFLEN];
|
||||
char title[BUFLEN];
|
||||
uint16_t bitrate;
|
||||
int ovol;
|
||||
};
|
||||
|
||||
struct neworkItem
|
||||
{
|
||||
char ssid[20];
|
||||
char password[40];
|
||||
};
|
||||
|
||||
class Config {
|
||||
public:
|
||||
config_t store;
|
||||
station_t station;
|
||||
theme_t theme;
|
||||
#if IR_PIN!=255
|
||||
int irindex;
|
||||
uint8_t irchck;
|
||||
ircodes_t ircodes;
|
||||
#endif
|
||||
neworkItem ssids[5];
|
||||
byte ssidsCount;
|
||||
uint16_t sleepfor;
|
||||
public:
|
||||
Config() {};
|
||||
void save();
|
||||
#if IR_PIN!=255
|
||||
void saveIR();
|
||||
#endif
|
||||
void init();
|
||||
void loadTheme();
|
||||
byte setVolume(byte val);
|
||||
void saveVolume();
|
||||
void setTone(int8_t bass, int8_t middle, int8_t trebble);
|
||||
void setBalance(int8_t balance);
|
||||
byte setLastStation(byte val);
|
||||
byte setCountStation(byte val);
|
||||
byte setLastSSID(byte 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 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 initPlaylist();
|
||||
void indexPlaylist();
|
||||
void fillPlMenu(char plmenu[][40], int from, byte count, bool removeNum = false);
|
||||
void setTimezone(int8_t tzh, int8_t tzm);
|
||||
void setTimezoneOffset(uint16_t tzo);
|
||||
uint16_t getTimezoneOffset();
|
||||
void setBrightness(bool dosave=false);
|
||||
void setDspOn(bool dspon);
|
||||
void sleepForAfter(uint16_t sleepfor, uint16_t sleepafter=0);
|
||||
private:
|
||||
template <class T> int eepromWrite(int ee, const T& value);
|
||||
template <class T> int eepromRead(int ee, T& value);
|
||||
void setDefaults();
|
||||
Ticker _sleepTimer;
|
||||
static void doSleep();
|
||||
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
|
||||
};
|
||||
|
||||
extern Config config;
|
||||
|
||||
#endif
|
||||
635
yoRadio/src/core/controls.cpp
Normal file
635
yoRadio/src/core/controls.cpp
Normal file
@@ -0,0 +1,635 @@
|
||||
#include "Arduino.h"
|
||||
#include "controls.h"
|
||||
#include "options.h"
|
||||
#include "config.h"
|
||||
#include "player.h"
|
||||
#include "display.h"
|
||||
#include "netserver.h"
|
||||
|
||||
long encOldPosition = 0;
|
||||
long enc2OldPosition = 0;
|
||||
int lpId = -1;
|
||||
|
||||
#define ISPUSHBUTTONS BTN_LEFT!=255 || BTN_CENTER!=255 || BTN_RIGHT!=255 || ENC_BTNB!=255 || BTN_UP!=255 || BTN_DOWN!=255 || ENC2_BTNB!=255
|
||||
#if ISPUSHBUTTONS
|
||||
#include "OneButton.h"
|
||||
OneButton button[] {{BTN_LEFT, true, BTN_INTERNALPULLUP}, {BTN_CENTER, true, BTN_INTERNALPULLUP}, {BTN_RIGHT, true, BTN_INTERNALPULLUP}, {ENC_BTNB, true, ENC_INTERNALPULLUP}, {BTN_UP, true, BTN_INTERNALPULLUP}, {BTN_DOWN, true, BTN_INTERNALPULLUP}, {ENC2_BTNB, true, ENC2_INTERNALPULLUP}};
|
||||
constexpr uint8_t nrOfButtons = sizeof(button) / sizeof(button[0]);
|
||||
#endif
|
||||
|
||||
#if ENC_HALFQUARD==false
|
||||
#define ENCODER_STEPS 4
|
||||
#elif ENC_HALFQUARD==true
|
||||
#define ENCODER_STEPS 2
|
||||
#elif ENC_HALFQUARD==255
|
||||
#define ENCODER_STEPS 1
|
||||
#endif
|
||||
#if ENC2_HALFQUARD==false
|
||||
#define ENCODER2_STEPS 4
|
||||
#elif ENC2_HALFQUARD==true
|
||||
#define ENCODER2_STEPS 2
|
||||
#elif ENC2_HALFQUARD==255
|
||||
#define ENCODER2_STEPS 1
|
||||
#endif
|
||||
|
||||
#if (ENC_BTNL!=255 && ENC_BTNR!=255) || (ENC2_BTNL!=255 && ENC2_BTNR!=255)
|
||||
#include "../yoEncoder/yoEncoder.h"
|
||||
#if (ENC_BTNL!=255 && ENC_BTNR!=255)
|
||||
yoEncoder encoder = yoEncoder(ENC_BTNL, ENC_BTNR, ENCODER_STEPS, ENC_INTERNALPULLUP);
|
||||
#endif
|
||||
#if (ENC2_BTNL!=255 && ENC2_BTNR!=255)
|
||||
yoEncoder encoder2 = yoEncoder(ENC2_BTNL, ENC2_BTNR, ENCODER2_STEPS, ENC2_INTERNALPULLUP);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TS_CS!=255
|
||||
#include <XPT2046_Touchscreen.h>
|
||||
XPT2046_Touchscreen ts(TS_CS);
|
||||
#endif
|
||||
|
||||
#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;
|
||||
const uint16_t kCaptureBufferSize = 1024;
|
||||
const uint8_t kTimeout = IR_TIMEOUT;
|
||||
const uint16_t kMinUnknownSize = 12;
|
||||
#define LEGACY_TIMING_INFO false
|
||||
|
||||
IRrecv irrecv(IR_PIN, kCaptureBufferSize, kTimeout, true);
|
||||
decode_results irResults;
|
||||
#endif
|
||||
|
||||
#if ENC_BTNL!=255
|
||||
void IRAM_ATTR readEncoderISR()
|
||||
{
|
||||
encoder.readEncoder_ISR();
|
||||
}
|
||||
#endif
|
||||
#if ENC2_BTNL!=255
|
||||
void IRAM_ATTR readEncoder2ISR()
|
||||
{
|
||||
encoder2.readEncoder_ISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
void initControls() {
|
||||
|
||||
#if ENC_BTNL!=255
|
||||
encoder.begin();
|
||||
encoder.setup(readEncoderISR);
|
||||
encoder.setBoundaries(0, 254, true);
|
||||
encoder.setAcceleration(config.store.encacc);
|
||||
#endif
|
||||
#if ENC2_BTNL!=255
|
||||
encoder2.begin();
|
||||
encoder2.setup(readEncoder2ISR);
|
||||
encoder2.setBoundaries(0, 254, true);
|
||||
encoder2.setAcceleration(config.store.encacc);
|
||||
#endif
|
||||
|
||||
#if ISPUSHBUTTONS
|
||||
for (int i = 0; i < nrOfButtons; i++)
|
||||
{
|
||||
if ((i == 0 && BTN_LEFT == 255) || (i == 1 && BTN_CENTER == 255) || (i == 2 && BTN_RIGHT == 255) || (i == 3 && ENC_BTNB == 255) || (i == 4 && BTN_UP == 255) || (i == 5 && BTN_DOWN == 255) || (i == 6 && ENC2_BTNB == 255)) continue;
|
||||
button[i].attachClick([](void* p) {
|
||||
onBtnClick((int)p);
|
||||
}, (void*)i);
|
||||
button[i].attachDoubleClick([](void* p) {
|
||||
onBtnDoubleClick((int)p);
|
||||
}, (void*)i);
|
||||
button[i].attachLongPressStart([](void* p) {
|
||||
onBtnLongPressStart((int)p);
|
||||
}, (void*)i);
|
||||
button[i].attachLongPressStop([](void* p) {
|
||||
onBtnLongPressStop((int)p);
|
||||
}, (void*)i);
|
||||
button[i].setClickTicks(BTN_CLICK_TICKS);
|
||||
button[i].setPressTicks(BTN_PRESS_TICKS);
|
||||
}
|
||||
#endif
|
||||
#if TS_CS!=255
|
||||
ts.begin();
|
||||
ts.setRotation(config.store.fliptouch?3:1);
|
||||
#endif
|
||||
#if IR_PIN!=255
|
||||
pinMode(IR_PIN, INPUT);
|
||||
assert(irutils::lowLevelSanityCheck() == 0);
|
||||
#if DECODE_HASH
|
||||
irrecv.setUnknownThreshold(kMinUnknownSize);
|
||||
#endif // DECODE_HASH
|
||||
irrecv.setTolerance(config.store.irtlp);
|
||||
irrecv.enableIRIn();
|
||||
#endif // IR_PIN!=255
|
||||
}
|
||||
|
||||
void loopControls() {
|
||||
if(display.mode()==LOST || display.mode()==UPDATING) return;
|
||||
if (ctrls_on_loop) ctrls_on_loop();
|
||||
#if ENC_BTNL!=255
|
||||
encoderLoop();
|
||||
#endif
|
||||
#if ENC2_BTNL!=255
|
||||
encoder2Loop();
|
||||
#endif
|
||||
#if ISPUSHBUTTONS
|
||||
for (unsigned i = 0; i < nrOfButtons; i++)
|
||||
{
|
||||
if ((i == 0 && BTN_LEFT == 255) || (i == 1 && BTN_CENTER == 255) || (i == 2 && BTN_RIGHT == 255) || (i == 3 && ENC_BTNB == 255) || (i == 4 && BTN_UP == 255) || (i == 5 && BTN_DOWN == 255) || (i == 6 && ENC2_BTNB == 255)) continue;
|
||||
button[i].tick();
|
||||
if (lpId >= 0) {
|
||||
if (DSP_MODEL == DSP_DUMMY && (lpId == 4 || lpId == 5)) continue;
|
||||
onBtnDuringLongPress(lpId);
|
||||
yield();
|
||||
}
|
||||
yield();
|
||||
}
|
||||
#endif
|
||||
#if IR_PIN!=255
|
||||
irLoop();
|
||||
#endif
|
||||
#if TS_CS!=255
|
||||
touchLoop();
|
||||
#endif
|
||||
yield();
|
||||
}
|
||||
|
||||
#if ENC_BTNL!=255
|
||||
void encoderLoop() {
|
||||
int8_t encoderDelta = encoder.encoderChanged();
|
||||
if (encoderDelta!=0)
|
||||
{
|
||||
controlsEvent(encoderDelta > 0, encoderDelta);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENC2_BTNL!=255
|
||||
void encoder2Loop() {
|
||||
int8_t encoderDelta = encoder2.encoderChanged();
|
||||
if (encoderDelta!=0)
|
||||
{
|
||||
uint8_t bp = 2;
|
||||
if (ENC2_BTNB != 255) {
|
||||
bp = digitalRead(ENC2_BTNB);
|
||||
}
|
||||
if (bp == HIGH && display.mode() == PLAYER) {
|
||||
display.putRequest(NEWMODE, STATIONS);
|
||||
while(display.mode() != STATIONS) {delay(10);}
|
||||
}
|
||||
controlsEvent(encoderDelta > 0, encoderDelta);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IR_PIN!=255
|
||||
void irBlink() {
|
||||
if (player.mode == STOPPED) {
|
||||
for (byte i = 0; i < 7; i++) {
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void irNum(byte num) {
|
||||
uint16_t s;
|
||||
if (display.numOfNextStation == 0 && num == 0) return;
|
||||
display.putRequest(NEWMODE, NUMBERS);
|
||||
if (display.numOfNextStation > UINT16_MAX / 10) return;
|
||||
s = display.numOfNextStation * 10 + num;
|
||||
if (s > config.store.countStation) return;
|
||||
display.numOfNextStation = s;
|
||||
display.putRequest(NEXTSTATION, s);
|
||||
}
|
||||
|
||||
void irLoop() {
|
||||
if (irrecv.decode(&irResults)) {
|
||||
if(irResults.value<256) return;
|
||||
if (netserver.irRecordEnable) {
|
||||
Serial.print(resultToHumanReadableBasic(&irResults));
|
||||
Serial.println("--------------------------");
|
||||
config.ircodes.irVals[config.irindex][config.irchck]=irResults.value;
|
||||
netserver.irToWs(typeToString(irResults.decode_type, irResults.repeat).c_str(), irResults.value);
|
||||
return;
|
||||
}
|
||||
if (!irResults.repeat/* && irResults.command!=0*/) {
|
||||
irVolRepeat = 0;
|
||||
}
|
||||
switch (irVolRepeat) {
|
||||
case 1: {
|
||||
controlsEvent(display.mode() == STATIONS ? false : true);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
controlsEvent(display.mode() == STATIONS ? true : false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(int target=0; target<17; target++){
|
||||
for(int j=0; j<3; j++){
|
||||
if(config.ircodes.irVals[target][j]==irResults.value){
|
||||
switch (target){
|
||||
case IR_PLAY: {
|
||||
irBlink();
|
||||
if (display.mode() == NUMBERS) {
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
player.play(display.numOfNextStation);
|
||||
display.numOfNextStation = 0;
|
||||
break;
|
||||
}
|
||||
onBtnClick(1);
|
||||
break;
|
||||
}
|
||||
case IR_PREV: {
|
||||
player.prev();
|
||||
break;
|
||||
}
|
||||
case IR_NEXT: {
|
||||
player.next();
|
||||
break;
|
||||
}
|
||||
case IR_UP: {
|
||||
controlsEvent(display.mode() == STATIONS ? false : true);
|
||||
irVolRepeat = 1;
|
||||
break;
|
||||
}
|
||||
case IR_DOWN: {
|
||||
controlsEvent(display.mode() == STATIONS ? true : false);
|
||||
irVolRepeat = 2;
|
||||
break;
|
||||
}
|
||||
case IR_HASH: {
|
||||
if (display.mode() == NUMBERS) {
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
display.numOfNextStation = 0;
|
||||
break;
|
||||
}
|
||||
display.putRequest(NEWMODE, display.mode() == PLAYER ? STATIONS : PLAYER);
|
||||
break;
|
||||
}
|
||||
case IR_0: {
|
||||
irNum(0);
|
||||
break;
|
||||
}
|
||||
case IR_1: {
|
||||
irNum(1);
|
||||
break;
|
||||
}
|
||||
case IR_2: {
|
||||
irNum(2);
|
||||
break;
|
||||
}
|
||||
case IR_3: {
|
||||
irNum(3);
|
||||
break;
|
||||
}
|
||||
case IR_4: {
|
||||
irNum(4);
|
||||
break;
|
||||
}
|
||||
case IR_5: {
|
||||
irNum(5);
|
||||
break;
|
||||
}
|
||||
case IR_6: {
|
||||
irNum(6);
|
||||
break;
|
||||
}
|
||||
case IR_7: {
|
||||
irNum(7);
|
||||
break;
|
||||
}
|
||||
case IR_8: {
|
||||
irNum(8);
|
||||
break;
|
||||
}
|
||||
case IR_9: {
|
||||
irNum(9);
|
||||
break;
|
||||
}
|
||||
case IR_AST: {
|
||||
break;
|
||||
}
|
||||
} /* switch (target) */
|
||||
target=17;
|
||||
break;
|
||||
} /* if(config.ircodes.irVals[target][j]==irResults.value) */
|
||||
} /* for(int j=0; j<3; j++) */
|
||||
} /* for(int target=0; target<16; target++) */
|
||||
} /* if (irrecv.decode(&irResults)) */
|
||||
}
|
||||
#endif // if IR_PIN!=255
|
||||
|
||||
#if TS_CS!=255
|
||||
#ifndef TS_X_MIN
|
||||
#define TS_X_MIN 400
|
||||
#endif
|
||||
#ifndef TS_X_MAX
|
||||
#define TS_X_MAX 3800
|
||||
#endif
|
||||
#ifndef TS_Y_MIN
|
||||
#define TS_Y_MIN 260
|
||||
#endif
|
||||
#ifndef TS_Y_MAX
|
||||
#define TS_Y_MAX 3800
|
||||
#endif
|
||||
#ifndef TS_STEPS
|
||||
#define TS_STEPS 40
|
||||
#endif
|
||||
|
||||
boolean wastouched = true;
|
||||
unsigned long touchdelay;
|
||||
uint16_t touchVol, touchStation;
|
||||
uint16_t oldTouchP[2];
|
||||
tsDirection_e direct;
|
||||
unsigned long touchLongPress;
|
||||
|
||||
tsDirection_e tsDirection(uint16_t x, uint16_t y) {
|
||||
int16_t dX = x - oldTouchP[0];
|
||||
int16_t dY = y - oldTouchP[1];
|
||||
if (abs(dX) > 20 || abs(dY) > 20) {
|
||||
if (abs(dX) > abs(dY)) {
|
||||
if (dX > 0) {
|
||||
return TSD_RIGHT;
|
||||
} else {
|
||||
return TSD_LEFT;
|
||||
}
|
||||
} else {
|
||||
if (dY > 0) {
|
||||
return TSD_DOWN;
|
||||
} else {
|
||||
return TSD_UP;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return TDS_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
void touchLoop() {
|
||||
if (!checklpdelay(100, touchdelay)) return;
|
||||
boolean istouched = ts.touched();
|
||||
if (istouched) {
|
||||
TS_Point p = ts.getPoint();
|
||||
uint16_t touchX = map(p.x, TS_X_MIN, TS_X_MAX, 0, dsp.width());
|
||||
uint16_t touchY = map(p.y, TS_Y_MIN, TS_Y_MAX, 0, dsp.height());
|
||||
if (!wastouched) { /* START TOUCH */
|
||||
oldTouchP[0] = touchX;
|
||||
oldTouchP[1] = touchY;
|
||||
touchVol = touchX;
|
||||
touchStation = touchY;
|
||||
direct = TDS_REQUEST;
|
||||
touchLongPress=millis();
|
||||
} else { /* SWIPE TOUCH */
|
||||
direct = tsDirection(touchX, touchY);
|
||||
switch (direct) {
|
||||
case TSD_LEFT:
|
||||
case TSD_RIGHT: {
|
||||
touchLongPress=millis();
|
||||
if(display.mode()==PLAYER || display.mode()==VOL){
|
||||
int16_t xDelta = map(abs(touchVol - touchX), 0, dsp.width(), 0, TS_STEPS);
|
||||
display.putRequest(NEWMODE, VOL);
|
||||
if (xDelta>1) {
|
||||
controlsEvent((touchVol - touchX)<0);
|
||||
touchVol = touchX;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TSD_UP:
|
||||
case TSD_DOWN: {
|
||||
touchLongPress=millis();
|
||||
if(display.mode()==PLAYER || display.mode()==STATIONS){
|
||||
int16_t yDelta = map(abs(touchStation - touchY), 0, dsp.height(), 0, TS_STEPS);
|
||||
display.putRequest(NEWMODE, STATIONS);
|
||||
if (yDelta>1) {
|
||||
controlsEvent((touchStation - touchY)<0);
|
||||
touchStation = touchY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (config.store.dbgtouch) {
|
||||
Serial.print(", x = ");
|
||||
Serial.print(p.x);
|
||||
Serial.print(", y = ");
|
||||
Serial.println(p.y);
|
||||
}
|
||||
} else {
|
||||
if (wastouched) {/* END TOUCH */
|
||||
if (direct == TDS_REQUEST) {
|
||||
uint32_t pressTicks = millis()-touchLongPress;
|
||||
if( pressTicks < BTN_PRESS_TICKS*2){
|
||||
if(pressTicks > 50) onBtnClick(EVT_BTNCENTER);
|
||||
}else{
|
||||
display.putRequest(NEWMODE, display.mode() == PLAYER ? STATIONS : PLAYER);
|
||||
}
|
||||
}
|
||||
direct = TSD_STAY;
|
||||
}
|
||||
}
|
||||
wastouched = istouched;
|
||||
}
|
||||
#endif // if TS_CS!=255
|
||||
|
||||
void onBtnLongPressStart(int id) {
|
||||
switch ((controlEvt_e)id) {
|
||||
case EVT_BTNLEFT:
|
||||
case EVT_BTNRIGHT:
|
||||
case EVT_BTNUP:
|
||||
case EVT_BTNDOWN: {
|
||||
lpId = id;
|
||||
break;
|
||||
}
|
||||
case EVT_BTNCENTER:
|
||||
case EVT_ENCBTNB: {
|
||||
display.putRequest(NEWMODE, display.mode() == PLAYER ? STATIONS : PLAYER);
|
||||
break;
|
||||
}
|
||||
case EVT_ENC2BTNB: {
|
||||
display.putRequest(NEWMODE, display.mode() == PLAYER ? VOL : PLAYER);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onBtnLongPressStop(int id) {
|
||||
switch ((controlEvt_e)id) {
|
||||
case EVT_BTNLEFT:
|
||||
case EVT_BTNRIGHT:
|
||||
case EVT_BTNUP:
|
||||
case EVT_BTNDOWN: {
|
||||
lpId = -1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long lpdelay;
|
||||
boolean checklpdelay(int m, unsigned long &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void onBtnDuringLongPress(int id) {
|
||||
if (checklpdelay(BTN_LONGPRESS_LOOP_DELAY, lpdelay)) {
|
||||
switch ((controlEvt_e)id) {
|
||||
case EVT_BTNLEFT: {
|
||||
controlsEvent(false);
|
||||
break;
|
||||
}
|
||||
case EVT_BTNRIGHT: {
|
||||
controlsEvent(true);
|
||||
break;
|
||||
}
|
||||
case EVT_BTNUP:
|
||||
case EVT_BTNDOWN: {
|
||||
if (display.mode() == PLAYER) {
|
||||
display.putRequest(NEWMODE, STATIONS);
|
||||
}
|
||||
if (display.mode() == STATIONS) {
|
||||
controlsEvent(id == EVT_BTNDOWN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void controlsEvent(bool toRight, int8_t volDelta) {
|
||||
if (display.mode() == NUMBERS) {
|
||||
display.numOfNextStation = 0;
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
}
|
||||
if (display.mode() != STATIONS) {
|
||||
display.putRequest(NEWMODE, VOL);
|
||||
if(volDelta!=0){
|
||||
int nv = config.store.volume+volDelta;
|
||||
if(nv<0) nv=0;
|
||||
if(nv>254) nv=254;
|
||||
player.setVol((byte)nv, false);
|
||||
}else{
|
||||
player.stepVol(toRight);
|
||||
}
|
||||
}
|
||||
if (display.mode() == STATIONS) {
|
||||
display.resetQueue();
|
||||
int p = toRight ? display.currentPlItem + 1 : display.currentPlItem - 1;
|
||||
if (p < 1) p = config.store.countStation;
|
||||
if (p > config.store.countStation) p = 1;
|
||||
display.currentPlItem = p;
|
||||
display.putRequest(DRAWPLAYLIST, p);
|
||||
}
|
||||
}
|
||||
|
||||
void onBtnClick(int id) {
|
||||
switch ((controlEvt_e)id) {
|
||||
case EVT_BTNLEFT: {
|
||||
controlsEvent(false);
|
||||
break;
|
||||
}
|
||||
case EVT_BTNCENTER:
|
||||
case EVT_ENCBTNB:
|
||||
case EVT_ENC2BTNB: {
|
||||
if (display.mode() == NUMBERS) {
|
||||
display.numOfNextStation = 0;
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
}
|
||||
if (display.mode() == PLAYER) {
|
||||
player.toggle();
|
||||
}
|
||||
if (display.mode() == STATIONS) {
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
player.play(display.currentPlItem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVT_BTNRIGHT: {
|
||||
controlsEvent(true);
|
||||
break;
|
||||
}
|
||||
case EVT_BTNUP:
|
||||
case EVT_BTNDOWN: {
|
||||
if (DSP_MODEL == DSP_DUMMY) {
|
||||
if (id == EVT_BTNUP) {
|
||||
player.next();
|
||||
} else {
|
||||
player.prev();
|
||||
}
|
||||
} else {
|
||||
if (display.mode() == PLAYER) {
|
||||
display.putRequest(NEWMODE, STATIONS);
|
||||
}
|
||||
if (display.mode() == STATIONS) {
|
||||
controlsEvent(id == EVT_BTNDOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onBtnDoubleClick(int id) {
|
||||
switch ((controlEvt_e)id) {
|
||||
case EVT_BTNLEFT: {
|
||||
if (display.mode() != PLAYER) return;
|
||||
player.prev();
|
||||
break;
|
||||
}
|
||||
case EVT_BTNCENTER:
|
||||
case EVT_ENCBTNB:
|
||||
case EVT_ENC2BTNB: {
|
||||
display.putRequest(NEWMODE, display.mode() == PLAYER ? VOL : PLAYER);
|
||||
break;
|
||||
}
|
||||
case EVT_BTNRIGHT: {
|
||||
if (display.mode() != PLAYER) return;
|
||||
player.next();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void setIRTolerance(uint8_t tl){
|
||||
config.store.irtlp=tl;
|
||||
config.save();
|
||||
#if IR_PIN!=255
|
||||
irrecv.setTolerance(config.store.irtlp);
|
||||
#endif
|
||||
}
|
||||
void setEncAcceleration(uint16_t acc){
|
||||
config.store.encacc=acc;
|
||||
config.save();
|
||||
#if ENC_BTNL!=255
|
||||
encoder.setAcceleration(config.store.encacc);
|
||||
#endif
|
||||
#if ENC2_BTNL!=255
|
||||
encoder2.setAcceleration(config.store.encacc);
|
||||
#endif
|
||||
}
|
||||
void flipTS(){
|
||||
#if TS_CS!=255
|
||||
ts.setRotation(config.store.fliptouch?3:1);
|
||||
#endif
|
||||
}
|
||||
38
yoRadio/src/core/controls.h
Normal file
38
yoRadio/src/core/controls.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef controls_h
|
||||
#define controls_h
|
||||
#include "options.h"
|
||||
|
||||
enum controlEvt_e { EVT_BTNLEFT, EVT_BTNCENTER, EVT_BTNRIGHT, EVT_ENCBTNB, EVT_BTNUP, EVT_BTNDOWN, EVT_ENC2BTNB };
|
||||
|
||||
enum tsDirection_e { TSD_STAY, TSD_LEFT, TSD_RIGHT, TSD_UP, TSD_DOWN, TDS_REQUEST };
|
||||
|
||||
#if IR_PIN!=255
|
||||
enum : uint8_t { IR_UP=0, IR_PREV=1, IR_PLAY=2, IR_NEXT=3, IR_DOWN=4, IR_1=5, IR_2=6, IR_3=7, IR_4=8, IR_5=9, IR_6=10, IR_7=11, IR_8=12, IR_9=13, IR_AST=14, IR_0=15, IR_HASH=16 };
|
||||
#endif
|
||||
|
||||
boolean checklpdelay(int m, unsigned long &tstamp);
|
||||
|
||||
void initControls();
|
||||
void loopControls();
|
||||
void encoderLoop();
|
||||
void encoder2Loop();
|
||||
void irLoop();
|
||||
void touchLoop();
|
||||
void irNum(byte num);
|
||||
void irBlink();
|
||||
void controlsEvent(bool toRight, int8_t volDelta = 0);
|
||||
|
||||
void onBtnClick(int id);
|
||||
void onBtnDoubleClick(int id);
|
||||
void onBtnDuringLongPress(int id);
|
||||
void onBtnLongPressStart(int id);
|
||||
void onBtnLongPressStop(int id);
|
||||
tsDirection_e tsDirection(uint16_t x, uint16_t y);
|
||||
|
||||
void setIRTolerance(uint8_t tl);
|
||||
void setEncAcceleration(uint16_t acc);
|
||||
void flipTS();
|
||||
|
||||
extern __attribute__((weak)) void ctrls_on_loop();
|
||||
|
||||
#endif
|
||||
511
yoRadio/src/core/display.cpp
Normal file
511
yoRadio/src/core/display.cpp
Normal file
@@ -0,0 +1,511 @@
|
||||
#include "options.h"
|
||||
|
||||
#include "WiFi.h"
|
||||
#include "time.h"
|
||||
#include "display.h"
|
||||
#include "player.h"
|
||||
#include "network.h"
|
||||
|
||||
|
||||
Display display;
|
||||
#ifdef USE_NEXTION
|
||||
Nextion nextion;
|
||||
#endif
|
||||
|
||||
#ifndef DUMMYDISPLAY
|
||||
//============================================================================================================================
|
||||
DspCore dsp;
|
||||
|
||||
Page *pages[] = { new Page(), new Page(), new Page() };
|
||||
|
||||
#ifndef CORE_STACK_SIZE
|
||||
#define CORE_STACK_SIZE 1024*3
|
||||
#endif
|
||||
#ifndef DSP_TASK_DELAY
|
||||
#define DSP_TASK_DELAY 2
|
||||
#endif
|
||||
|
||||
TaskHandle_t DspTask;
|
||||
QueueHandle_t displayQueue;
|
||||
|
||||
void returnPlayer(){
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
}
|
||||
|
||||
void Display::_createDspTask(){
|
||||
xTaskCreatePinnedToCore(loopDspTask, "DspTask", CORE_STACK_SIZE, NULL, 4, &DspTask, !xPortGetCoreID());
|
||||
}
|
||||
|
||||
void loopDspTask(void * pvParameters){
|
||||
while(true){
|
||||
if(displayQueue==NULL) break;
|
||||
display.loop();
|
||||
vTaskDelay(DSP_TASK_DELAY);
|
||||
}
|
||||
vTaskDelete( NULL );
|
||||
DspTask=NULL;
|
||||
}
|
||||
|
||||
void Display::init() {
|
||||
#ifdef USE_NEXTION
|
||||
nextion.begin();
|
||||
#endif
|
||||
_bootStep = 0;
|
||||
dsp.initDisplay();
|
||||
displayQueue=NULL;
|
||||
displayQueue = xQueueCreate( 5, sizeof( requestParams_t ) );
|
||||
while(displayQueue==NULL){;}
|
||||
_createDspTask();
|
||||
while(!_bootStep==0) { delay(10); }
|
||||
//_pager.begin();
|
||||
//_bootScreen();
|
||||
}
|
||||
|
||||
void Display::_bootScreen(){
|
||||
_boot = new Page();
|
||||
_boot->addWidget(new ProgressWidget(bootWdtConf, bootPrgConf, BOOT_PRG_COLOR, 0));
|
||||
_bootstring = (TextWidget*) &_boot->addWidget(new TextWidget(bootstrConf, 50, true, BOOT_TXT_COLOR, 0));
|
||||
_pager.addPage(_boot);
|
||||
_pager.setPage(_boot, true);
|
||||
dsp.drawLogo(bootLogoTop);
|
||||
_bootStep = 1;
|
||||
}
|
||||
|
||||
void Display::_buildPager(){
|
||||
_meta.init("*", metaConf, config.theme.meta, config.theme.metabg);
|
||||
_title1.init("*", title1Conf, config.theme.title1, config.theme.background);
|
||||
_clock.init(clockConf, 0, 0);
|
||||
#if DSP_MODEL==DSP_NOKIA5110
|
||||
_plcurrent.init("*", playlistConf, 0, 1);
|
||||
#else
|
||||
_plcurrent.init("*", playlistConf, config.theme.meta, config.theme.metabg);
|
||||
#endif
|
||||
#ifndef HIDE_TITLE2
|
||||
_title2 = new ScrollWidget("*", title2Conf, config.theme.title2, config.theme.background);
|
||||
#endif
|
||||
#if !defined(DSP_LCD) && DSP_MODEL!=DSP_NOKIA5110
|
||||
_plbackground = new FillWidget(playlBGConf, config.theme.metafill);
|
||||
_metabackground = new FillWidget(metaBGConf, config.theme.metafill);
|
||||
#endif
|
||||
#if DSP_MODEL==DSP_NOKIA5110
|
||||
_plbackground = new FillWidget(playlBGConf, 1);
|
||||
//_metabackground = new FillWidget(metaBGConf, 1);
|
||||
#endif
|
||||
#ifndef HIDE_VU
|
||||
_vuwidget = new VuWidget(vuConf, bandsConf, config.theme.vumax, config.theme.vumin, config.theme.background);
|
||||
#endif
|
||||
#ifndef HIDE_VOLBAR
|
||||
_volbar = new SliderWidget(volbarConf, config.theme.volbarin, config.theme.background, 254, config.theme.volbarout);
|
||||
#endif
|
||||
#ifndef HIDE_HEAPBAR
|
||||
_heapbar = new SliderWidget(heapbarConf, config.theme.buffer, config.theme.background, psramInit()?300000:1600 * AUDIOBUFFER_MULTIPLIER2);
|
||||
#endif
|
||||
#ifndef HIDE_VOL
|
||||
_voltxt = new TextWidget(voltxtConf, 10, false, config.theme.vol, config.theme.background);
|
||||
#endif
|
||||
#ifndef HIDE_IP
|
||||
_volip = new TextWidget(iptxtConf, 30, false, config.theme.ip, config.theme.background);
|
||||
#endif
|
||||
#ifndef HIDE_RSSI
|
||||
_rssi = new TextWidget(rssiConf, 20, false, config.theme.rssi, config.theme.background);
|
||||
#endif
|
||||
_nums.init(numConf, 10, false, config.theme.digit, config.theme.background);
|
||||
#ifndef HIDE_WEATHER
|
||||
_weather = new ScrollWidget("*", weatherConf, config.theme.weather, config.theme.background);
|
||||
#endif
|
||||
|
||||
if(_volbar) _footer.addWidget( _volbar);
|
||||
if(_voltxt) _footer.addWidget( _voltxt);
|
||||
if(_volip) _footer.addWidget( _volip);
|
||||
if(_rssi) _footer.addWidget( _rssi);
|
||||
if(_heapbar) _footer.addWidget( _heapbar);
|
||||
|
||||
if(_metabackground) pages[PG_PLAYER]->addWidget( _metabackground);
|
||||
pages[PG_PLAYER]->addWidget(&_meta);
|
||||
pages[PG_PLAYER]->addWidget(&_title1);
|
||||
if(_title2) pages[PG_PLAYER]->addWidget(_title2);
|
||||
if(_weather) pages[PG_PLAYER]->addWidget(_weather);
|
||||
#ifdef BITRATE_FULL
|
||||
_fullbitrate = new BitrateWidget(fullbitrateConf, config.theme.bitrate, config.theme.background);
|
||||
pages[PG_PLAYER]->addWidget( _fullbitrate);
|
||||
#else
|
||||
_bitrate = new TextWidget(bitrateConf, 30, false, config.theme.bitrate, config.theme.background);
|
||||
pages[PG_PLAYER]->addWidget( _bitrate);
|
||||
#endif
|
||||
if(_vuwidget) pages[PG_PLAYER]->addWidget( _vuwidget);
|
||||
pages[PG_PLAYER]->addWidget(&_clock);
|
||||
pages[PG_PLAYER]->addPage(&_footer);
|
||||
|
||||
if(_metabackground) pages[PG_DIALOG]->addWidget( _metabackground);
|
||||
pages[PG_DIALOG]->addWidget(&_meta);
|
||||
pages[PG_DIALOG]->addWidget(&_nums);
|
||||
|
||||
#if !defined(DSP_LCD) && DSP_MODEL!=DSP_NOKIA5110
|
||||
pages[PG_DIALOG]->addPage(&_footer);
|
||||
#endif
|
||||
|
||||
if(_plbackground) pages[PG_PLAYLIST]->addWidget( _plbackground);
|
||||
pages[PG_PLAYLIST]->addWidget(&_plcurrent);
|
||||
|
||||
for(const auto& p: pages) _pager.addPage(p);
|
||||
}
|
||||
|
||||
void Display::_apScreen() {
|
||||
if(_boot) _pager.removePage(_boot);
|
||||
#ifndef DSP_LCD
|
||||
_boot = new Page();
|
||||
#if DSP_MODEL!=DSP_NOKIA5110
|
||||
_boot->addWidget(new FillWidget(metaBGConf, config.theme.metafill));
|
||||
#endif
|
||||
ScrollWidget *bootTitle = (ScrollWidget*) &_boot->addWidget(new ScrollWidget("*", apTitleConf, config.theme.meta, config.theme.metabg));
|
||||
bootTitle->setText("ёRadio AP Mode");
|
||||
TextWidget *apname = (TextWidget*) &_boot->addWidget(new TextWidget(apNameConf, 30, false, config.theme.title1, config.theme.background));
|
||||
apname->setText(apNameTxt);
|
||||
TextWidget *apname2 = (TextWidget*) &_boot->addWidget(new TextWidget(apName2Conf, 30, false, config.theme.metabg, config.theme.background));
|
||||
apname2->setText(apSsid);
|
||||
TextWidget *appass = (TextWidget*) &_boot->addWidget(new TextWidget(apPassConf, 30, false, config.theme.title1, config.theme.background));
|
||||
appass->setText(apPassTxt);
|
||||
TextWidget *appass2 = (TextWidget*) &_boot->addWidget(new TextWidget(apPass2Conf, 30, false, config.theme.metabg, config.theme.background));
|
||||
appass2->setText(apPassword);
|
||||
ScrollWidget *bootSett = (ScrollWidget*) &_boot->addWidget(new ScrollWidget("*", apSettConf, config.theme.title2, config.theme.background));
|
||||
bootSett->setText(WiFi.softAPIP().toString().c_str(), apSettFmt);
|
||||
_pager.addPage(_boot);
|
||||
_pager.setPage(_boot);
|
||||
#else
|
||||
dsp.apScreen();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Display::_start() {
|
||||
if(_boot) _pager.removePage(_boot);
|
||||
#ifdef USE_NEXTION
|
||||
nextion.wake();
|
||||
#endif
|
||||
if (network.status != CONNECTED) {
|
||||
_apScreen();
|
||||
#ifdef USE_NEXTION
|
||||
nextion.apScreen();
|
||||
#endif
|
||||
_bootStep = 2;
|
||||
return;
|
||||
}
|
||||
#ifdef USE_NEXTION
|
||||
nextion.putcmd("page player");
|
||||
nextion.start();
|
||||
#endif
|
||||
_buildPager();
|
||||
_mode = PLAYER;
|
||||
config.setTitle(const_PlReady);
|
||||
|
||||
if(_heapbar) _heapbar->lock(!config.store.audioinfo);
|
||||
|
||||
if(_weather) _weather->lock(!config.store.showweather);
|
||||
if(_weather && config.store.showweather) _weather->setText(const_getWeather);
|
||||
|
||||
if(_vuwidget) _vuwidget->lock();
|
||||
if(_rssi) _rssi->setText(WiFi.RSSI(), rssiFmt);
|
||||
#ifndef HIDE_IP
|
||||
if(_volip) _volip->setText(WiFi.localIP().toString().c_str(), iptxtFmt);
|
||||
#endif
|
||||
_pager.setPage( pages[PG_PLAYER]);
|
||||
_volume();
|
||||
_station();
|
||||
_time(false);
|
||||
_bootStep = 2;
|
||||
}
|
||||
|
||||
void Display::_showDialog(const char *title){
|
||||
dsp.setScrollId(NULL);
|
||||
_pager.setPage( pages[PG_DIALOG]);
|
||||
#ifdef META_MOVE
|
||||
_meta.moveTo(metaMove);
|
||||
#endif
|
||||
_meta.setAlign(WA_CENTER);
|
||||
_meta.setText(title);
|
||||
}
|
||||
|
||||
void Display::_setReturnTicker(uint8_t time_s){
|
||||
_returnTicker.detach();
|
||||
_returnTicker.once(time_s, returnPlayer);
|
||||
}
|
||||
|
||||
void Display::_swichMode(displayMode_e newmode) {
|
||||
#ifdef USE_NEXTION
|
||||
nextion.swichMode(newmode);
|
||||
#endif
|
||||
if (newmode == _mode || network.status != CONNECTED) return;
|
||||
_mode = newmode;
|
||||
dsp.setScrollId(NULL);
|
||||
if (newmode == PLAYER) {
|
||||
numOfNextStation = 0;
|
||||
_returnTicker.detach();
|
||||
#ifdef META_MOVE
|
||||
_meta.moveBack();
|
||||
#endif
|
||||
_meta.setAlign(WA_LEFT);
|
||||
_meta.setText(config.station.name);
|
||||
_nums.setText("");
|
||||
_pager.setPage( pages[PG_PLAYER]);
|
||||
}
|
||||
if (newmode == VOL) {
|
||||
#ifndef HIDE_IP
|
||||
_showDialog(const_DlgVolume);
|
||||
#else
|
||||
_showDialog(WiFi.localIP().toString().c_str());
|
||||
#endif
|
||||
}
|
||||
if (newmode == LOST) _showDialog(const_DlgLost);
|
||||
if (newmode == UPDATING) _showDialog(const_DlgUpdate);
|
||||
if (newmode == INFO || newmode == SETTINGS || newmode == TIMEZONE || newmode == WIFI) _showDialog(const_DlgNextion);
|
||||
if (newmode == NUMBERS) _showDialog("");
|
||||
if (newmode == STATIONS) {
|
||||
_pager.setPage( pages[PG_PLAYLIST]);
|
||||
_plcurrent.setText("");
|
||||
currentPlItem = config.store.lastStation;
|
||||
_drawPlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
void Display::resetQueue(){
|
||||
xQueueReset(displayQueue);
|
||||
}
|
||||
|
||||
void Display::_drawPlaylist() {
|
||||
char buf[PLMITEMLENGHT];
|
||||
dsp.drawPlaylist(currentPlItem, buf);
|
||||
_plcurrent.setText(buf);
|
||||
/*#ifdef USE_NEXTION
|
||||
nextion.drawPlaylist(currentPlItem);
|
||||
#endif*/
|
||||
_setReturnTicker(30);
|
||||
}
|
||||
|
||||
void Display::_drawNextStationNum(uint16_t num) {
|
||||
char plMenu[1][40];
|
||||
char currentItemText[40] = {0};
|
||||
config.fillPlMenu(plMenu, num, 1, true);
|
||||
strlcpy(currentItemText, plMenu[0], 39);
|
||||
_setReturnTicker(30);
|
||||
_meta.setText(currentItemText);
|
||||
_nums.setText(num, "%d");
|
||||
/*#ifdef USE_NEXTION
|
||||
nextion.drawNextStationNum(num);
|
||||
#endif*/
|
||||
}
|
||||
|
||||
void Display::putRequest(displayRequestType_e type, int payload){
|
||||
if(displayQueue==NULL) return;
|
||||
requestParams_t request;
|
||||
request.type = type;
|
||||
request.payload = payload;
|
||||
xQueueSend(displayQueue, &request, portMAX_DELAY);
|
||||
#ifdef USE_NEXTION
|
||||
nextion.putRequest(request);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Display::_layoutChange(bool played){
|
||||
if(config.store.vumeter){
|
||||
if(played){
|
||||
if(_vuwidget) _vuwidget->unlock();
|
||||
_clock.moveTo(clockMove);
|
||||
if(_weather) _weather->moveTo(weatherMoveVU);
|
||||
}else{
|
||||
if(_vuwidget) if(!_vuwidget->locked()) _vuwidget->lock();
|
||||
_clock.moveBack();
|
||||
if(_weather) _weather->moveBack();
|
||||
}
|
||||
}else{
|
||||
if(played){
|
||||
if(_weather) _weather->moveTo(weatherMove);
|
||||
_clock.moveBack();
|
||||
}else{
|
||||
if(_weather) _weather->moveBack();
|
||||
_clock.moveBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Display::loop() {
|
||||
if(_bootStep==0) {
|
||||
_pager.begin();
|
||||
_bootScreen();
|
||||
return;
|
||||
}
|
||||
if(displayQueue==NULL) return;
|
||||
_pager.loop();
|
||||
#ifdef USE_NEXTION
|
||||
nextion.loop();
|
||||
#endif
|
||||
requestParams_t request;
|
||||
if(xQueueReceive(displayQueue, &request, 20)){
|
||||
switch (request.type){
|
||||
case NEWMODE: _swichMode((displayMode_e)request.payload); break;
|
||||
case CLOCK:
|
||||
if(_mode==PLAYER) _time();
|
||||
/*#ifdef USE_NEXTION
|
||||
if(_mode==TIMEZONE) nextion.localTime(network.timeinfo);
|
||||
if(_mode==INFO) nextion.rssi();
|
||||
#endif*/
|
||||
break;
|
||||
case NEWTITLE: _title(); break;
|
||||
case NEWSTATION: _station(); break;
|
||||
case NEXTSTATION: _drawNextStationNum(request.payload); break;
|
||||
case DRAWPLAYLIST: _drawPlaylist(); break;
|
||||
case DRAWVOL: _volume(); break;
|
||||
case DBITRATE: {
|
||||
char buf[20];
|
||||
snprintf(buf, 20, bitrateFmt, config.station.bitrate);
|
||||
if(_bitrate) { _bitrate->setText(config.station.bitrate==0?"":buf); }
|
||||
if(_fullbitrate) {
|
||||
_fullbitrate->setBitrate(config.station.bitrate);
|
||||
_fullbitrate->setFormat(BF_MP3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AUDIOINFO: if(_heapbar) { _heapbar->lock(!config.store.audioinfo); _heapbar->setValue(player.inBufferFilled()); } break;
|
||||
case SHOWVUMETER: {
|
||||
if(_vuwidget){
|
||||
_vuwidget->lock(!config.store.vumeter);
|
||||
_layoutChange(player.isRunning());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHOWWEATHER: {
|
||||
if(_weather) _weather->lock(!config.store.showweather);
|
||||
if(!config.store.showweather){
|
||||
#ifndef HIDE_IP
|
||||
if(_volip) _volip->setText(WiFi.localIP().toString().c_str(), iptxtFmt);
|
||||
#endif
|
||||
}else{
|
||||
if(_weather) _weather->setText(const_getWeather);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NEWWEATHER: {
|
||||
if(_weather && network.weatherBuf) _weather->setText(network.weatherBuf);
|
||||
break;
|
||||
}
|
||||
case BOOTSTRING: {
|
||||
if(_bootstring) _bootstring->setText(config.ssids[request.payload].ssid, bootstrFmt);
|
||||
/*#ifdef USE_NEXTION
|
||||
char buf[50];
|
||||
snprintf(buf, 50, bootstrFmt, config.ssids[request.payload].ssid);
|
||||
nextion.bootString(buf);
|
||||
#endif*/
|
||||
break;
|
||||
}
|
||||
case DSPRSSI: if(_rssi){ _rssi->setText(request.payload, rssiFmt); } if (_heapbar && config.store.audioinfo) _heapbar->setValue(player.inBufferFilled()); break;
|
||||
case PSTART: _layoutChange(true); break;
|
||||
case PSTOP: _layoutChange(false); break;
|
||||
case DSP_START: _start(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
dsp.loop();
|
||||
}
|
||||
|
||||
void Display::_station() {
|
||||
_meta.setAlign(WA_LEFT);
|
||||
_meta.setText(config.station.name);
|
||||
/*#ifdef USE_NEXTION
|
||||
nextion.newNameset(config.station.name);
|
||||
nextion.bitrate(config.station.bitrate);
|
||||
nextion.bitratePic(ICON_NA);
|
||||
#endif*/
|
||||
}
|
||||
|
||||
char *split(char *str, const char *delim) {
|
||||
char *dmp = strstr(str, delim);
|
||||
if (dmp == NULL) return NULL;
|
||||
*dmp = '\0';
|
||||
return dmp + strlen(delim);
|
||||
}
|
||||
|
||||
void Display::_title() {
|
||||
if (strlen(config.station.title) > 0) {
|
||||
char tmpbuf[strlen(config.station.title)+1];
|
||||
strlcpy(tmpbuf, config.station.title, strlen(config.station.title)+1);
|
||||
char *stitle = split(tmpbuf, " - ");
|
||||
if(stitle && _title2){
|
||||
_title1.setText(tmpbuf);
|
||||
_title2->setText(stitle);
|
||||
}else{
|
||||
_title1.setText(config.station.title);
|
||||
if(_title2) _title2->setText("");
|
||||
}
|
||||
/*#ifdef USE_NEXTION
|
||||
nextion.newTitle(config.station.title);
|
||||
#endif*/
|
||||
if (player_on_track_change) player_on_track_change();
|
||||
}
|
||||
}
|
||||
|
||||
void Display::_time(bool redraw) {
|
||||
_clock.draw();
|
||||
/*#ifdef USE_NEXTION
|
||||
nextion.printClock(network.timeinfo);
|
||||
#endif*/
|
||||
}
|
||||
|
||||
void Display::_volume() {
|
||||
if(_volbar) _volbar->setValue(config.store.volume);
|
||||
#ifndef HIDE_VOL
|
||||
if(_voltxt) _voltxt->setText(config.store.volume, voltxtFmt);
|
||||
#endif
|
||||
if(_mode==VOL) {
|
||||
_setReturnTicker(3);
|
||||
_nums.setText(config.store.volume, numtxtFmt);
|
||||
}
|
||||
/*#ifdef USE_NEXTION
|
||||
nextion.setVol(config.store.volume, _mode == VOL);
|
||||
#endif*/
|
||||
}
|
||||
|
||||
void Display::flip(){ dsp.flip(); }
|
||||
|
||||
void Display::invert(){ dsp.invert(); }
|
||||
|
||||
void Display::setContrast(){
|
||||
#if DSP_MODEL==DSP_NOKIA5110
|
||||
dsp.setContrast(config.store.contrast);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Display::deepsleep(){
|
||||
#if defined(LCD_I2C) || defined(DSP_OLED) || BRIGHTNESS_PIN!=255
|
||||
dsp.sleep();
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void Display::wakeup(){
|
||||
#if defined(LCD_I2C) || defined(DSP_OLED) || BRIGHTNESS_PIN!=255
|
||||
dsp.wake();
|
||||
#endif
|
||||
}
|
||||
//============================================================================================================================
|
||||
#else // !DUMMYDISPLAY
|
||||
//============================================================================================================================
|
||||
void Display::init(){
|
||||
#ifdef USE_NEXTION
|
||||
nextion.begin(true);
|
||||
#endif
|
||||
}
|
||||
void Display::_start(){
|
||||
#ifdef USE_NEXTION
|
||||
nextion.start();
|
||||
#endif
|
||||
}
|
||||
void Display::putRequest(displayRequestType_e type, int payload){
|
||||
if(type==DSP_START) _start();
|
||||
#ifdef USE_NEXTION
|
||||
requestParams_t request;
|
||||
request.type = type;
|
||||
request.payload = payload;
|
||||
nextion.putRequest(request);
|
||||
#endif
|
||||
}
|
||||
//============================================================================================================================
|
||||
#endif // DUMMYDISPLAY
|
||||
113
yoRadio/src/core/display.h
Normal file
113
yoRadio/src/core/display.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef display_h
|
||||
#define display_h
|
||||
#include "options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Ticker.h>
|
||||
#include "config.h"
|
||||
|
||||
#include "../displays/dspcore.h"
|
||||
|
||||
enum displayMode_e { PLAYER, VOL, STATIONS, NUMBERS, LOST, UPDATING, INFO, SETTINGS, TIMEZONE, WIFI, CLEAR };
|
||||
enum pages_e : uint8_t { PG_PLAYER=0, PG_DIALOG=1, PG_PLAYLIST=2 };
|
||||
//enum dialogType_e : uint8_t { DG_NONE=0, DG_VOLUME=1, DG_LOST=2, DG_UPDATING=3, DG_NEXTION=4 };
|
||||
|
||||
enum displayRequestType_e { BOOTSTRING, NEWMODE, CLOCK, NEWTITLE, NEWSTATION, NEXTSTATION, DRAWPLAYLIST, DRAWVOL, DBITRATE, AUDIOINFO, SHOWVUMETER, DSPRSSI, SHOWWEATHER, NEWWEATHER, PSTOP, PSTART, DSP_START };
|
||||
struct requestParams_t
|
||||
{
|
||||
displayRequestType_e type;
|
||||
int payload;
|
||||
};
|
||||
|
||||
#if NEXTION_RX!=255 && NEXTION_TX!=255
|
||||
#define USE_NEXTION
|
||||
#include "../displays/nextion.h"
|
||||
#endif
|
||||
|
||||
#ifndef DUMMYDISPLAY
|
||||
void loopDspTask(void * pvParameters);
|
||||
|
||||
class Display {
|
||||
public:
|
||||
uint16_t currentPlItem;
|
||||
uint16_t numOfNextStation;
|
||||
displayMode_e _mode;
|
||||
public:
|
||||
Display() {};
|
||||
displayMode_e mode() { return _mode; }
|
||||
void mode(displayMode_e m) { _mode=m; }
|
||||
void init();
|
||||
void loop();
|
||||
void _start();
|
||||
bool ready() { return _bootStep==2; }
|
||||
void resetQueue();
|
||||
void putRequest(displayRequestType_e type, int payload=0);
|
||||
void flip();
|
||||
void invert();
|
||||
bool deepsleep();
|
||||
void wakeup();
|
||||
void setContrast();
|
||||
private:
|
||||
ScrollWidget _meta, _title1, _plcurrent;
|
||||
ScrollWidget *_weather;
|
||||
ScrollWidget *_title2;
|
||||
BitrateWidget *_fullbitrate;
|
||||
FillWidget *_metabackground, *_plbackground;
|
||||
SliderWidget *_volbar, *_heapbar;
|
||||
Pager _pager;
|
||||
Page _footer;
|
||||
VuWidget *_vuwidget;
|
||||
NumWidget _nums;
|
||||
ProgressWidget _testprogress;
|
||||
ClockWidget _clock;
|
||||
Page *_boot;
|
||||
TextWidget *_bootstring, *_volip, *_voltxt, *_rssi, *_bitrate;
|
||||
Ticker _returnTicker;
|
||||
uint8_t _bootStep;
|
||||
void _time(bool redraw = false);
|
||||
void _apScreen();
|
||||
void _swichMode(displayMode_e newmode);
|
||||
void _drawPlaylist();
|
||||
void _volume();
|
||||
void _title();
|
||||
void _station();
|
||||
void _drawNextStationNum(uint16_t num);
|
||||
void _createDspTask();
|
||||
void _showDialog(const char *title);
|
||||
void _buildPager();
|
||||
void _bootScreen();
|
||||
void _setReturnTicker(uint8_t time_s);
|
||||
void _layoutChange(bool played);
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class Display {
|
||||
public:
|
||||
uint16_t currentPlItem;
|
||||
uint16_t numOfNextStation;
|
||||
displayMode_e _mode;
|
||||
public:
|
||||
Display() {};
|
||||
displayMode_e mode() { return _mode; }
|
||||
void mode(displayMode_e m) { _mode=m; }
|
||||
void init();
|
||||
void _start();
|
||||
void putRequest(displayRequestType_e type, int payload=0);
|
||||
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 flip(){}
|
||||
void invert(){}
|
||||
void setContrast(){}
|
||||
bool deepsleep(){return true;}
|
||||
void wakeup(){}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
extern Display display;
|
||||
|
||||
#endif
|
||||
126
yoRadio/src/core/mqtt.cpp
Normal file
126
yoRadio/src/core/mqtt.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "mqtt.h"
|
||||
|
||||
#ifdef MQTT_HOST
|
||||
#include "WiFi.h"
|
||||
|
||||
#include "telnet.h"
|
||||
#include "player.h"
|
||||
#include "config.h"
|
||||
|
||||
AsyncMqttClient mqttClient;
|
||||
TimerHandle_t mqttReconnectTimer;
|
||||
|
||||
void connectToMqtt() {
|
||||
mqttClient.connect();
|
||||
}
|
||||
|
||||
void mqttInit() {
|
||||
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
|
||||
mqttClient.onConnect(onMqttConnect);
|
||||
mqttClient.onDisconnect(onMqttDisconnect);
|
||||
mqttClient.onMessage(onMqttMessage);
|
||||
if(strlen(MQTT_USER)>0) mqttClient.setCredentials(MQTT_USER, MQTT_PASS);
|
||||
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
||||
connectToMqtt();
|
||||
}
|
||||
|
||||
void onMqttConnect(bool sessionPresent) {
|
||||
char buf[140];
|
||||
sprintf(buf, "%s%s", MQTT_ROOT_TOPIC, "command");
|
||||
mqttClient.subscribe(buf, 2);
|
||||
mqttPublishStatus();
|
||||
mqttPublishVolume();
|
||||
mqttPublishPlaylist();
|
||||
}
|
||||
|
||||
void mqttPublishStatus() {
|
||||
if(mqttClient.connected()){
|
||||
char topic[140], status[BUFLEN*3];
|
||||
sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "status");
|
||||
sprintf(status, "{\"status\": %d, \"station\": %d, \"name\": \"%s\", \"title\": \"%s\"}", player.mode==PLAYING?1:0, config.store.lastStation, config.station.name, config.station.title);
|
||||
mqttClient.publish(topic, 0, true, status);
|
||||
}
|
||||
}
|
||||
|
||||
void mqttPublishPlaylist() {
|
||||
if(mqttClient.connected()){
|
||||
char topic[140], playlist[140];
|
||||
sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "playlist");
|
||||
sprintf(playlist, "http://%s%s", WiFi.localIP().toString().c_str(), PLAYLIST_PATH);
|
||||
mqttClient.publish(topic, 0, true, playlist);
|
||||
}
|
||||
}
|
||||
|
||||
void mqttPublishVolume(){
|
||||
if(mqttClient.connected()){
|
||||
char topic[140], vol[5];
|
||||
sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "volume");
|
||||
sprintf(vol, "%d", config.store.volume);
|
||||
mqttClient.publish(topic, 0, true, vol);
|
||||
}
|
||||
}
|
||||
|
||||
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||
if (WiFi.isConnected()) {
|
||||
xTimerStart(mqttReconnectTimer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
if (len == 0) return;
|
||||
char buf[20];
|
||||
strlcpy(buf, payload, len+1);
|
||||
if (strcmp(buf, "prev") == 0) {
|
||||
player.prev();
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "next") == 0) {
|
||||
player.next();
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "toggle") == 0) {
|
||||
player.toggle();
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "stop") == 0) {
|
||||
player.mode = STOPPED;
|
||||
telnet.info();
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "start") == 0 || strcmp(buf, "play") == 0) {
|
||||
//player.play(config.store.lastStation);
|
||||
player.request.station = config.store.lastStation;
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "boot") == 0 || strcmp(buf, "reboot") == 0) {
|
||||
ESP.restart();
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "volm") == 0) {
|
||||
player.stepVol(false);
|
||||
return;
|
||||
}
|
||||
if (strcmp(buf, "volp") == 0) {
|
||||
player.stepVol(true);
|
||||
return;
|
||||
}
|
||||
int volume;
|
||||
if ( sscanf(buf, "vol %d", &volume) == 1) {
|
||||
if (volume < 0) volume = 0;
|
||||
if (volume > 254) volume = 254;
|
||||
player.setVol(volume, false);
|
||||
return;
|
||||
}
|
||||
//uint16_t sb;
|
||||
int sb;
|
||||
if (sscanf(buf, "play %d", &sb) == 1 ) {
|
||||
if (sb < 1) sb = 1;
|
||||
if (sb >= config.store.countStation) sb = config.store.countStation;
|
||||
//player.play(sb);
|
||||
player.request.station = (uint16_t)sb;
|
||||
player.request.doSave = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifdef MQTT_HOST
|
||||
21
yoRadio/src/core/mqtt.h
Normal file
21
yoRadio/src/core/mqtt.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef mqtt_h
|
||||
#define mqtt_h
|
||||
|
||||
#if __has_include("../../mqttoptions.h")
|
||||
#include "../../mqttoptions.h"
|
||||
#include <AsyncMqttClient.h>
|
||||
|
||||
|
||||
void mqttInit();
|
||||
void connectToMqtt();
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
||||
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
|
||||
void mqttPublishStatus();
|
||||
void mqttPublishPlaylist();
|
||||
void mqttPublishVolume();
|
||||
|
||||
#endif // if __has_include("mqttoptions.h")
|
||||
|
||||
|
||||
#endif
|
||||
738
yoRadio/src/core/netserver.cpp
Normal file
738
yoRadio/src/core/netserver.cpp
Normal file
@@ -0,0 +1,738 @@
|
||||
#include "netserver.h"
|
||||
#include <SPIFFS.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "player.h"
|
||||
#include "telnet.h"
|
||||
#include "display.h"
|
||||
#include "options.h"
|
||||
#include "network.h"
|
||||
#include "mqtt.h"
|
||||
#include "controls.h"
|
||||
#include <Update.h>
|
||||
|
||||
#ifndef MIN_MALLOC
|
||||
#define MIN_MALLOC 24112
|
||||
#endif
|
||||
|
||||
//#define CORS_DEBUG
|
||||
|
||||
NetServer netserver;
|
||||
|
||||
AsyncWebServer webserver(80);
|
||||
AsyncWebSocket websocket("/ws");
|
||||
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);
|
||||
|
||||
bool shouldReboot = false;
|
||||
#ifdef MQTT_HOST
|
||||
Ticker mqttplaylistticker;
|
||||
bool mqttplaylistblock = false;
|
||||
void mqttplaylistSend() {
|
||||
mqttplaylistblock = true;
|
||||
mqttplaylistticker.detach();
|
||||
mqttPublishPlaylist();
|
||||
mqttplaylistblock = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
char* updateError() {
|
||||
static char ret[140] = {0};
|
||||
sprintf(ret, "Update failed with error (%d)<br /> %s", (int)Update.getError(), Update.errorString());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool NetServer::begin() {
|
||||
importRequest = IMDONE;
|
||||
irRecordEnable = false;
|
||||
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");
|
||||
#ifdef CORS_DEBUG
|
||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Origin"), F("*"));
|
||||
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), F("content-type"));
|
||||
#endif
|
||||
webserver.begin();
|
||||
websocket.onEvent(onWsEvent);
|
||||
webserver.addHandler(&websocket);
|
||||
|
||||
//echo -n "helle?" | socat - udp-datagram:255.255.255.255:44490,broadcast
|
||||
if (udp.listen(44490)) {
|
||||
udp.onPacket([](AsyncUDPPacket packet) {
|
||||
if (strcmp((char*)packet.data(), "helle?") == 0)
|
||||
packet.println(WiFi.localIP());
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
AsyncWebServerResponse *response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback, processor);
|
||||
xSemaphoreTake(player.playmutex, portMAX_DELAY);
|
||||
request->send(response);
|
||||
xSemaphoreGive(player.playmutex);
|
||||
}
|
||||
|
||||
void NetServer::loop() {
|
||||
if (shouldReboot) {
|
||||
Serial.println("Rebooting...");
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
}
|
||||
websocket.cleanupClients();
|
||||
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;
|
||||
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, "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;
|
||||
config.save();
|
||||
display.putRequest(AUDIOINFO);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "vumeter") == 0) {
|
||||
byte valb = atoi(val);
|
||||
config.store.vumeter = valb;
|
||||
config.save();
|
||||
display.putRequest(SHOWVUMETER);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "softap") == 0) {
|
||||
byte valb = atoi(val);
|
||||
config.store.softapdelay = valb;
|
||||
config.save();
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "invertdisplay") == 0) {
|
||||
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;
|
||||
config.save();
|
||||
display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "fliptouch") == 0) {
|
||||
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;
|
||||
config.save();
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "flipscreen") == 0) {
|
||||
byte valb = atoi(val);
|
||||
config.store.flipscreen = valb;
|
||||
config.save();
|
||||
display.flip();
|
||||
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;
|
||||
config.setBrightness(true);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "screenon") == 0) {
|
||||
byte valb = atoi(val);
|
||||
config.setDspOn(valb == 1);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "contrast") == 0) {
|
||||
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;
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "tzm") == 0) {
|
||||
int vali = atoi(val);
|
||||
config.store.tzMin = vali;
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "sntp2") == 0) {
|
||||
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) {
|
||||
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) {
|
||||
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1);
|
||||
tzdone = true;
|
||||
}
|
||||
if (tzdone) {
|
||||
//network.requestTimeSync(true);
|
||||
network.forceTimeSync = true;
|
||||
config.save();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "volsteps") == 0) {
|
||||
uint8_t valb = atoi(val);
|
||||
config.store.volsteps = valb;
|
||||
config.save();
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "encacceleration") == 0) {
|
||||
uint16_t valb = atoi(val);
|
||||
setEncAcceleration(valb);
|
||||
config.store.encacc = valb;
|
||||
config.save();
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "irtlp") == 0) {
|
||||
uint8_t valb = atoi(val);
|
||||
setIRTolerance(valb);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "showweather") == 0) {
|
||||
uint8_t valb = atoi(val);
|
||||
config.store.showweather = valb == 1;
|
||||
config.save();
|
||||
network.trueWeather=false;
|
||||
network.forceWeather = true;
|
||||
display.putRequest(SHOWWEATHER);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "lat") == 0) {
|
||||
strlcpy(config.store.weatherlat, val, 10);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "lon") == 0) {
|
||||
strlcpy(config.store.weatherlon, val, 10);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "key") == 0) {
|
||||
strlcpy(config.store.weatherkey, val, 64);
|
||||
config.save();
|
||||
network.trueWeather=false;
|
||||
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.save();
|
||||
display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER);
|
||||
requestOnChange(GETSYSTEM, clientId);
|
||||
return;
|
||||
}
|
||||
if (strcmp(val, "screen") == 0) {
|
||||
config.store.flipscreen = false;
|
||||
display.flip();
|
||||
config.store.invertdisplay = false;
|
||||
display.invert();
|
||||
config.store.dspon = true;
|
||||
config.store.brightness = 100;
|
||||
config.setBrightness(false);
|
||||
config.store.contrast = 55;
|
||||
display.setContrast();
|
||||
config.store.numplaylist = false;
|
||||
config.save();
|
||||
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.save();
|
||||
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2);
|
||||
network.forceTimeSync = true;
|
||||
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.save();
|
||||
network.trueWeather=false;
|
||||
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;
|
||||
setEncAcceleration(200);
|
||||
setIRTolerance(40);
|
||||
requestOnChange(GETCONTROLS, clientId);
|
||||
return;
|
||||
}
|
||||
} /* EOF RESETS */
|
||||
if (strcmp(cmd, "volume") == 0) {
|
||||
byte v = atoi(val);
|
||||
player.setVol(v, false);
|
||||
}
|
||||
if (strcmp(cmd, "balance") == 0) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
// xSemaphoreTake(player.playmutex, portMAX_DELAY);
|
||||
return;
|
||||
}
|
||||
if (strcmp(cmd, "submitplaylistdone") == 0) {
|
||||
#ifdef MQTT_HOST
|
||||
//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;
|
||||
irValsToWs();
|
||||
if (config.irindex < 0) config.saveIR();
|
||||
}
|
||||
if (strcmp(cmd, "chkid") == 0) {
|
||||
config.irchck = atoi(val);
|
||||
}
|
||||
if (strcmp(cmd, "irclr") == 0) {
|
||||
byte cl = atoi(val);
|
||||
config.ircodes.irVals[config.irindex][cl] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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); }
|
||||
}
|
||||
|
||||
bool NetServer::importPlaylist() {
|
||||
File tempfile = SPIFFS.open(TMP_PATH, "r");
|
||||
if (!tempfile) {
|
||||
return false;
|
||||
}
|
||||
char sName[BUFLEN], sUrl[BUFLEN];
|
||||
int sOvol;
|
||||
String line = tempfile.readStringUntil('\n');
|
||||
if (config.parseCSV(line.c_str(), sName, sUrl, sOvol)) {
|
||||
File playlistfile = SPIFFS.open(PLAYLIST_PATH, "w");
|
||||
playlistfile.println(line);
|
||||
while (tempfile.available()) {
|
||||
line = tempfile.readStringUntil('\n');
|
||||
if (config.parseCSV(line.c_str(), sName, sUrl, sOvol)) {
|
||||
playlistfile.println(line);
|
||||
}
|
||||
}
|
||||
playlistfile.close();
|
||||
tempfile.close();
|
||||
SPIFFS.remove(TMP_PATH);
|
||||
requestOnChange(PLAYLISTSAVED, 0);
|
||||
return true;
|
||||
}
|
||||
if (config.parseJSON(line.c_str(), sName, sUrl, sOvol)) {
|
||||
File playlistfile = SPIFFS.open(PLAYLIST_PATH, "w");
|
||||
String wline = String(sName) + "\t" + String(sUrl) + "\t" + String(sOvol);
|
||||
playlistfile.println(wline);
|
||||
while (tempfile.available()) {
|
||||
line = tempfile.readStringUntil('\n');
|
||||
if (config.parseJSON(line.c_str(), sName, sUrl, sOvol)) {
|
||||
wline = String(sName) + "\t" + String(sUrl) + "\t" + String(sOvol);
|
||||
playlistfile.println(wline);
|
||||
}
|
||||
}
|
||||
playlistfile.close();
|
||||
tempfile.close();
|
||||
SPIFFS.remove(TMP_PATH);
|
||||
requestOnChange(PLAYLISTSAVED, 0);
|
||||
return true;
|
||||
}
|
||||
tempfile.close();
|
||||
SPIFFS.remove(TMP_PATH);
|
||||
return false;
|
||||
}
|
||||
#ifndef DSP_NOT_FLIPPED
|
||||
#define DSP_CAN_FLIPPED true
|
||||
#else
|
||||
#define DSP_CAN_FLIPPED false
|
||||
#endif
|
||||
#if !defined(HIDE_WEATHER) && (!defined(DUMMYDISPLAY) && !defined(USE_NEXTION))
|
||||
#define SHOW_WEATHER true
|
||||
#else
|
||||
#define SHOW_WEATHER false
|
||||
#endif
|
||||
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); break;
|
||||
case GETACTIVE: {
|
||||
bool dbgact = false, nxtn=false;
|
||||
String act = F("\"group_wifi\",");
|
||||
if (network.status == CONNECTED) {
|
||||
act += F("\"group_system\",");
|
||||
if (BRIGHTNESS_PIN != 255 || DSP_CAN_FLIPPED || DSP_MODEL == DSP_NOKIA5110 || dbgact) act += F("\"group_display\",");
|
||||
#ifdef USE_NEXTION
|
||||
act += F("\"group_nextion\",");
|
||||
if (!SHOW_WEATHER || dbgact) act += F("\"group_weather\",");
|
||||
nxtn=true;
|
||||
#endif
|
||||
#if defined(LCD_I2C) || defined(DSP_OLED)
|
||||
act += F("\"group_oled\",");
|
||||
#endif
|
||||
#ifndef HIDE_VU
|
||||
act += F("\"group_vu\",");
|
||||
#endif
|
||||
if (BRIGHTNESS_PIN != 255 || nxtn || dbgact) act += F("\"group_brightness\",");
|
||||
if (DSP_CAN_FLIPPED || dbgact) act += F("\"group_tft\",");
|
||||
if (TS_CS != 255 || dbgact) act += F("\"group_touch\",");
|
||||
if (DSP_MODEL == DSP_NOKIA5110) act += F("\"group_nokia\",");
|
||||
act += F("\"group_timezone\",");
|
||||
if (SHOW_WEATHER || dbgact) act += F("\"group_weather\",");
|
||||
act += F("\"group_controls\",");
|
||||
if (ENC_BTNL != 255 || ENC2_BTNL != 255 || dbgact) act += F("\"group_encoder\",");
|
||||
if (IR_PIN != 255 || dbgact) act += F("\"group_ir\",");
|
||||
}
|
||||
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); 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); break;
|
||||
case BALANCE: sprintf (buf, "{\"balance\": %d}", config.store.balance); break;
|
||||
}
|
||||
if (strlen(buf) > 0) {
|
||||
if (clientId == 0) { websocket.textAll(buf); }else{ websocket.text(clientId, buf); }
|
||||
#ifdef MQTT_HOST
|
||||
if (clientId == 0 && (request == STATION || request == ITEM || request == TITLE || request == MODE)) mqttPublishStatus();
|
||||
if (clientId == 0 && request == VOLUME) mqttPublishVolume();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
String processor(const String& var) { // %Templates%
|
||||
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) {
|
||||
request->_tempFile = SPIFFS.open(TMP_PATH , "w");
|
||||
}
|
||||
if (len) {
|
||||
request->_tempFile.write(data, len);
|
||||
//TODO check index+len size
|
||||
}
|
||||
if (final) {
|
||||
request->_tempFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
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()); 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 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;
|
||||
}
|
||||
}
|
||||
if (network.status == CONNECTED) {
|
||||
bool commandFound=false;
|
||||
if (request->hasArg("start")) { player.request.station = config.store.lastStation; commandFound=true; }
|
||||
if (request->hasArg("stop")) { player.mode = STOPPED; config.setTitle(const_PlStopped); commandFound=true; }
|
||||
if (request->hasArg("toggle")) { player.toggle(); commandFound=true; }
|
||||
if (request->hasArg("prev")) { player.prev(); commandFound=true; }
|
||||
if (request->hasArg("next")) { player.next(); commandFound=true; }
|
||||
if (request->hasArg("volm")) { player.stepVol(false); commandFound=true; }
|
||||
if (request->hasArg("volp")) { player.stepVol(true); commandFound=true; }
|
||||
|
||||
if (request->hasArg("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);
|
||||
commandFound=true;
|
||||
}
|
||||
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);
|
||||
commandFound=true;
|
||||
}
|
||||
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;
|
||||
commandFound=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);
|
||||
commandFound=true;
|
||||
DBGVB("[%s] vol=%d", __func__, v);
|
||||
}
|
||||
if (request->hasArg("dspon")) {
|
||||
AsyncWebParameter* p = request->getParam("dspon", request->method() == HTTP_POST);
|
||||
int d = atoi(p->value().c_str());
|
||||
config.setDspOn(d!=0);
|
||||
commandFound=true;
|
||||
}
|
||||
if (request->hasArg("dim")) {
|
||||
AsyncWebParameter* p = request->getParam("dim", request->method() == HTTP_POST);
|
||||
int d = atoi(p->value().c_str());
|
||||
if (d < 0) d = 0;
|
||||
if (d > 100) d = 100;
|
||||
config.store.brightness = (uint8_t)d;
|
||||
config.setBrightness(true);
|
||||
commandFound=true;
|
||||
}
|
||||
if (request->hasArg("sleep")) {
|
||||
AsyncWebParameter* sfor = request->getParam("sleep", request->method() == HTTP_POST);
|
||||
int sford = atoi(sfor->value().c_str());
|
||||
int safterd = 0;
|
||||
if(request->hasArg("after")){
|
||||
AsyncWebParameter* safter = request->getParam("after", request->method() == HTTP_POST);
|
||||
safterd = atoi(safter->value().c_str());
|
||||
}
|
||||
if(sford > 0 && safterd >= 0){
|
||||
request->send(200);
|
||||
config.sleepForAfter(sford, safterd);
|
||||
commandFound=true;
|
||||
}
|
||||
}
|
||||
if (request->params() > 0) {
|
||||
request->send(commandFound?200:404);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (request->params() > 0) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
yoRadio/src/core/netserver.h
Normal file
41
yoRadio/src/core/netserver.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef netserver_h
|
||||
#define netserver_h
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "ESPAsyncWebServer.h"
|
||||
#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 import_e : uint8_t { IMDONE=0, IMPL=1, IMWIFI=2 };
|
||||
|
||||
class NetServer {
|
||||
public:
|
||||
import_e importRequest;
|
||||
bool resumePlay;
|
||||
char chunkedPathBuffer[40];
|
||||
public:
|
||||
NetServer() {};
|
||||
bool begin();
|
||||
void loop();
|
||||
void requestOnChange(requestType_e request, uint8_t clientId);
|
||||
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);
|
||||
#if IR_PIN!=255
|
||||
bool irRecordEnable;
|
||||
void irToWs(const char* protocol, uint64_t irvalue);
|
||||
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;
|
||||
|
||||
#endif
|
||||
288
yoRadio/src/core/network.cpp
Normal file
288
yoRadio/src/core/network.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
#include "network.h"
|
||||
#include "WiFi.h"
|
||||
#include "display.h"
|
||||
#include "options.h"
|
||||
#include "config.h"
|
||||
#include "telnet.h"
|
||||
#include "netserver.h"
|
||||
|
||||
Network network;
|
||||
|
||||
TaskHandle_t syncTaskHandle;
|
||||
bool getWeather(char *wstr);
|
||||
void doSync(void * pvParameters);
|
||||
|
||||
void ticks() {
|
||||
static const uint16_t weatherSyncInterval=1800;
|
||||
//static const uint16_t weatherSyncIntervalFail=10;
|
||||
static const uint16_t timeSyncInterval=3600;
|
||||
static uint16_t timeSyncTicks = 0;
|
||||
static uint16_t weatherSyncTicks = 0;
|
||||
static bool divrssi;
|
||||
timeSyncTicks++;
|
||||
weatherSyncTicks++;
|
||||
divrssi = !divrssi;
|
||||
if(network.forceTimeSync || network.forceWeather){
|
||||
xTaskCreatePinnedToCore(doSync, "doSync", 1024 * 4, NULL, 0, &syncTaskHandle, 0);
|
||||
}
|
||||
if(timeSyncTicks >= timeSyncInterval){
|
||||
timeSyncTicks=0;
|
||||
network.forceTimeSync = true;
|
||||
}
|
||||
if(weatherSyncTicks >= weatherSyncInterval){
|
||||
weatherSyncTicks=0;
|
||||
network.forceWeather = true;
|
||||
}
|
||||
|
||||
if(network.timeinfo.tm_year>100) {
|
||||
network.timeinfo.tm_sec++;
|
||||
mktime(&network.timeinfo);
|
||||
display.putRequest(CLOCK);
|
||||
}
|
||||
|
||||
if(divrssi) {
|
||||
int rs = WiFi.RSSI();
|
||||
netserver.setRSSI(rs);
|
||||
display.putRequest(DSPRSSI, rs);
|
||||
}
|
||||
}
|
||||
|
||||
#define DBGAP false
|
||||
|
||||
void Network::begin() {
|
||||
config.initNetwork();
|
||||
ctimer.detach();
|
||||
forceTimeSync = forceWeather = true;
|
||||
if (config.ssidsCount == 0 || DBGAP) {
|
||||
raiseSoftAP();
|
||||
return;
|
||||
}
|
||||
byte ls = (config.store.lastSSID == 0 || config.store.lastSSID > config.ssidsCount) ? 0 : config.store.lastSSID - 1;
|
||||
byte startedls = ls;
|
||||
byte errcnt = 0;
|
||||
WiFi.mode(WIFI_STA);
|
||||
while (true) {
|
||||
Serial.printf("[BOOT]\tAttempt to connect to %s...\n", config.ssids[ls].ssid);
|
||||
display.putRequest(BOOTSTRING, ls);
|
||||
WiFi.begin(config.ssids[ls].ssid, config.ssids[ls].password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(500);
|
||||
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
|
||||
errcnt++;
|
||||
if (errcnt > 16) {
|
||||
errcnt = 0;
|
||||
ls++;
|
||||
if (ls > config.ssidsCount - 1) ls = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WiFi.status() != WL_CONNECTED && ls == startedls) {
|
||||
raiseSoftAP();
|
||||
return;
|
||||
}
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
config.setLastSSID(ls + 1);
|
||||
break; // отстрелялись
|
||||
}
|
||||
}
|
||||
Serial.println(".");
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
status = CONNECTED;
|
||||
WiFi.setSleep(false);
|
||||
|
||||
weatherBuf=NULL;
|
||||
trueWeather = false;
|
||||
#if (DSP_MODEL!=DSP_DUMMY || defined(USE_NEXTION)) && !defined(HIDE_WEATHER)
|
||||
weatherBuf = (char *) malloc(sizeof(char) * WEATHER_STRING_L);
|
||||
memset(weatherBuf, 0, WEATHER_STRING_L);
|
||||
#endif
|
||||
|
||||
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);
|
||||
}else if(strlen(config.store.sntp1)>0){
|
||||
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1);
|
||||
}
|
||||
ctimer.attach(1, ticks);
|
||||
if (network_on_connect) network_on_connect();
|
||||
}
|
||||
|
||||
void Network::requestTimeSync(bool withTelnetOutput, uint8_t clientId) {
|
||||
if (withTelnetOutput) {
|
||||
char timeStringBuff[50];
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &timeinfo);
|
||||
if (config.store.tzHour < 0) {
|
||||
telnet.printf(clientId, "##SYS.DATE#: %s%03d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin);
|
||||
} else {
|
||||
telnet.printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rebootTime() {
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void Network::raiseSoftAP() {
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP(apSsid, apPassword);
|
||||
Serial.printf("\n\nRunning in AP mode.\nConnect to AP %s with password %s for settings.\n\n", apSsid, apPassword);
|
||||
status = SOFT_AP;
|
||||
if(config.store.softapdelay>0)
|
||||
rtimer.once(config.store.softapdelay*60, rebootTime);
|
||||
}
|
||||
|
||||
void Network::requestWeatherSync(){
|
||||
display.putRequest(NEWWEATHER);
|
||||
}
|
||||
|
||||
|
||||
void doSync( void * pvParameters ) {
|
||||
static uint8_t tsFailCnt = 0;
|
||||
//static uint8_t wsFailCnt = 0;
|
||||
if(network.forceTimeSync){
|
||||
network.forceTimeSync = false;
|
||||
if(getLocalTime(&network.timeinfo)){
|
||||
tsFailCnt = 0;
|
||||
network.forceTimeSync = false;
|
||||
mktime(&network.timeinfo);
|
||||
display.putRequest(CLOCK);
|
||||
network.requestTimeSync(true);
|
||||
}else{
|
||||
if(tsFailCnt<4){
|
||||
network.forceTimeSync = true;
|
||||
tsFailCnt++;
|
||||
}else{
|
||||
network.forceTimeSync = false;
|
||||
tsFailCnt=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(network.weatherBuf && (strlen(config.store.weatherkey)!=0 && config.store.showweather) && network.forceWeather){
|
||||
network.forceWeather = false;
|
||||
network.trueWeather=getWeather(network.weatherBuf);
|
||||
}
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
|
||||
bool getWeather(char *wstr) {
|
||||
#if (DSP_MODEL!=DSP_DUMMY || defined(USE_NEXTION)) && !defined(HIDE_WEATHER)
|
||||
WiFiClient client;
|
||||
const char* host = "api.openweathermap.org";
|
||||
|
||||
if (!client.connect(host, 80)) {
|
||||
Serial.println("## OPENWEATHERMAP ###: connection failed");
|
||||
return false;
|
||||
}
|
||||
char httpget[250] = {0};
|
||||
sprintf(httpget, "GET /data/2.5/weather?lat=%s&lon=%s&units=%s&lang=%s&appid=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", config.store.weatherlat, config.store.weatherlon, weatherUnits, weatherLang, config.store.weatherkey, host);
|
||||
client.print(httpget);
|
||||
unsigned long timeout = millis();
|
||||
while (client.available() == 0) {
|
||||
if (millis() - timeout > 2000UL) {
|
||||
Serial.println("## OPENWEATHERMAP ###: client available timeout !");
|
||||
client.stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
timeout = millis();
|
||||
String line = "";
|
||||
if (client.connected()) {
|
||||
while (client.available())
|
||||
{
|
||||
line = client.readStringUntil('\n');
|
||||
if (strstr(line.c_str(), "\"temp\"") != NULL) {
|
||||
client.stop();
|
||||
break;
|
||||
}
|
||||
if ((millis() - timeout) > 500)
|
||||
{
|
||||
client.stop();
|
||||
Serial.println("## OPENWEATHERMAP ###: client read timeout !");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strstr(line.c_str(), "\"temp\"") == NULL) {
|
||||
Serial.println("## OPENWEATHERMAP ###: weather not found !");
|
||||
return false;
|
||||
}
|
||||
char *tmpe;
|
||||
char *tmps;
|
||||
const char* cursor = line.c_str();
|
||||
char desc[120], temp[20], hum[20], press[20], icon[5];
|
||||
|
||||
tmps = strstr(cursor, "\"description\":\"");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;}
|
||||
tmps += 15;
|
||||
tmpe = strstr(tmps, "\",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;}
|
||||
strlcpy(desc, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
|
||||
// "ясно","icon":"01d"}],
|
||||
tmps = strstr(cursor, "\"icon\":\"");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: icon not found !"); return false;}
|
||||
tmps += 8;
|
||||
tmpe = strstr(tmps, "\"}");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: icon not found !"); return false;}
|
||||
strlcpy(icon, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
|
||||
tmps = strstr(cursor, "\"temp\":");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;}
|
||||
tmps += 7;
|
||||
tmpe = strstr(tmps, ",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;}
|
||||
strlcpy(temp, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
float tempf = atof(temp);
|
||||
|
||||
tmps = strstr(cursor, "\"pressure\":");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;}
|
||||
tmps += 11;
|
||||
tmpe = strstr(tmps, ",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;}
|
||||
strlcpy(press, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
int pressi = (float)atoi(press) / 1.333;
|
||||
|
||||
tmps = strstr(cursor, "humidity\":");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;}
|
||||
tmps += 10;
|
||||
tmpe = strstr(tmps, ",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;}
|
||||
strlcpy(hum, tmps, tmpe - tmps + 1);
|
||||
|
||||
#ifdef USE_NEXTION
|
||||
nextion.putcmdf("press_txt.txt=\"%dmm\"", pressi);
|
||||
nextion.putcmdf("hum_txt.txt=\"%d%%\"", atoi(hum));
|
||||
char cmd[30];
|
||||
snprintf(cmd, sizeof(cmd)-1,"temp_txt.txt=\"%.1f\"", tempf);
|
||||
nextion.putcmd(cmd);
|
||||
int iconofset;
|
||||
if(strstr(icon,"01")!=NULL) iconofset = 0;
|
||||
else if(strstr(icon,"02")!=NULL) iconofset = 1;
|
||||
else if(strstr(icon,"03")!=NULL) iconofset = 2;
|
||||
else if(strstr(icon,"04")!=NULL) iconofset = 3;
|
||||
else if(strstr(icon,"09")!=NULL) iconofset = 4;
|
||||
else if(strstr(icon,"10")!=NULL) iconofset = 5;
|
||||
else if(strstr(icon,"11")!=NULL) iconofset = 6;
|
||||
else if(strstr(icon,"13")!=NULL) iconofset = 7;
|
||||
else if(strstr(icon,"50")!=NULL) iconofset = 8;
|
||||
else iconofset = 9;
|
||||
nextion.putcmd("cond_img.pic", 50+iconofset);
|
||||
nextion.weatherVisible(1);
|
||||
#endif
|
||||
|
||||
Serial.printf("## OPENWEATHERMAP ###: description: %s, temp:%.1f C, pressure:%dmmHg, humidity:%s%%\n", desc, tempf, pressi, hum);
|
||||
#ifdef WEATHER_FMT_SHORT
|
||||
sprintf(wstr, weatherFmt, tempf, pressi, hum);
|
||||
#else
|
||||
sprintf(wstr, weatherFmt, desc, tempf, pressi, hum);
|
||||
#endif
|
||||
network.requestWeatherSync();
|
||||
return true;
|
||||
#endif // if (DSP_MODEL!=DSP_DUMMY || defined(USE_NEXTION)) && !defined(HIDE_WEATHER)
|
||||
return false;
|
||||
}
|
||||
37
yoRadio/src/core/network.h
Normal file
37
yoRadio/src/core/network.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef network_h
|
||||
#define network_h
|
||||
#include <Ticker.h>
|
||||
#include "time.h"
|
||||
|
||||
#define apSsid "yoRadioAP"
|
||||
#define apPassword "12345987"
|
||||
//#define TSYNC_DELAY 10800000 // 1000*60*60*3 = 3 hours
|
||||
#define TSYNC_DELAY 3600000 // 1000*60*60 = 1 hour
|
||||
#define WEATHER_STRING_L 254
|
||||
|
||||
enum n_Status_e { CONNECTED, SOFT_AP, FAILED };
|
||||
|
||||
class Network {
|
||||
public:
|
||||
n_Status_e status;
|
||||
struct tm timeinfo;
|
||||
bool firstRun, forceTimeSync, forceWeather;
|
||||
//uint8_t tsFailCnt, wsFailCnt;
|
||||
public:
|
||||
Network() {};
|
||||
void begin();
|
||||
void requestTimeSync(bool withTelnetOutput=false, uint8_t clientId=0);
|
||||
void requestWeatherSync();
|
||||
Ticker ctimer;
|
||||
char *weatherBuf;
|
||||
bool trueWeather;
|
||||
private:
|
||||
Ticker rtimer;
|
||||
void raiseSoftAP();
|
||||
};
|
||||
|
||||
extern Network network;
|
||||
|
||||
extern __attribute__((weak)) void network_on_connect();
|
||||
|
||||
#endif
|
||||
335
yoRadio/src/core/options.h
Normal file
335
yoRadio/src/core/options.h
Normal file
@@ -0,0 +1,335 @@
|
||||
#ifndef options_h
|
||||
#define options_h
|
||||
|
||||
#define VERSION "0.8.00b"
|
||||
|
||||
/*******************************************************
|
||||
DO NOT EDIT THIS FILE.
|
||||
ALL YOUR SETTINGS WILL BE OVERWRITTEN DURING THE UPDATE.
|
||||
STORE YOUR SETTINGS IN THE *** myoptions.h *** FILE.
|
||||
********************************************************/
|
||||
|
||||
#if __has_include("../../myoptions.h")
|
||||
#include "../../myoptions.h" /* <- write your variable values here */
|
||||
#endif
|
||||
#if __has_include("../../mytheme.h")
|
||||
#include "../../mytheme.h" /* <- Theme file */
|
||||
#endif
|
||||
|
||||
/*******************************************************
|
||||
|
||||
The connection tables are located here https://github.com/e2002/yoradio#connection-tables
|
||||
|
||||
********************************************************/
|
||||
|
||||
#define DSP_DUMMY 0 // without display
|
||||
#define DSP_ST7735 1 // 160x128 1.8' or 128x128 1.44' or 160x80 0.96' https://aliexpress.com/item/1005002822797745.html
|
||||
#define DSP_SSD1306 2 // 128x64 0.96' https://aliexpress.com/item/1005001621806398.html
|
||||
#define DSP_NOKIA5110 3 // 84x48 1.6' https://aliexpress.com/item/1005001621837569.html
|
||||
#define DSP_ST7789 4 // 320x240 2.4' https://aliexpress.com/item/32960241206.html
|
||||
#define DSP_SH1106 5 // 128x64 1.3' https://aliexpress.com/item/32683094040.html
|
||||
#define DSP_1602I2C 6 // 16x2 https://aliexpress.com/item/32305776560.html
|
||||
#define DSP_SSD1306x32 7 // 128x32 0.91' https://aliexpress.com/item/32798439084.html
|
||||
#define DSP_SSD1327 8 // 128x128 1.5' https://aliexpress.com/item/1005001414175498.html
|
||||
#define DSP_ILI9341 9 // 320x240 3.2' https://aliexpress.com/item/33048191074.html
|
||||
#define DSP_SSD1305 10 // 128x64 2.4' SSD1305 and SSD1309 SPI https://aliexpress.com/item/32950307344.html
|
||||
#define DSP_SH1107 11 // 128x64 1.3' https://aliexpress.com/item/4000551696674.html
|
||||
#define DSP_1602 12 // 16x2 https://aliexpress.com/item/32685016568.html
|
||||
#define DSP_GC9106 13 // 160x80 0.96' (looks like ST7735S, but it's not him) https://aliexpress.com/item/32947890530.html
|
||||
#define DSP_2004I2C 14 // 20x4 https://aliexpress.com/item/32783128355.html
|
||||
#define DSP_2004 15 // 20x4 https://aliexpress.com/item/32783128355.html
|
||||
#define DSP_SSD1305I2C 16 // 128x64 2.4' SSD1305 and SSD1309 I2C https://aliexpress.com/item/32950307344.html
|
||||
#define DSP_ILI9225 17 // 220x176 2.0' https://aliexpress.com/item/32952021835.html
|
||||
#define DSP_ST7789_240 18 // 240x240 1.3' https://aliexpress.com/item/32996979276.html
|
||||
/* !!! DSP_ST7789_240 requires further development when used in conjunction with the VS1053 module !!! See the link https://www.instructables.com/Adding-CS-Pin-to-13-LCD/ */
|
||||
|
||||
#define DSP_CUSTOM 101 // your display
|
||||
|
||||
#ifndef DSP_MODEL
|
||||
#define DSP_MODEL DSP_DUMMY
|
||||
#endif
|
||||
|
||||
/* TFT DISPLAY */
|
||||
#ifndef TFT_CS
|
||||
#define TFT_CS 5
|
||||
#endif
|
||||
#ifndef TFT_RST
|
||||
#define TFT_RST 15 // Or set to -1 and connect to Esp EN pin
|
||||
#endif
|
||||
#ifndef TFT_DC
|
||||
#define TFT_DC 4
|
||||
#endif
|
||||
|
||||
/* NEXTION */
|
||||
#ifndef NEXTION_RX
|
||||
#define NEXTION_RX 255
|
||||
#endif
|
||||
#ifndef NEXTION_TX
|
||||
#define NEXTION_TX 255
|
||||
#endif
|
||||
|
||||
/* OLED I2C DISPLAY */
|
||||
#ifndef I2C_SDA
|
||||
#define I2C_SDA 21
|
||||
#endif
|
||||
#ifndef I2C_SCL
|
||||
#define I2C_SCL 22
|
||||
#endif
|
||||
#ifndef I2C_RST
|
||||
#define I2C_RST -1
|
||||
#endif
|
||||
|
||||
/* VS1053 */
|
||||
#ifndef VS1053_CS
|
||||
#define VS1053_CS 255 // 27
|
||||
#endif
|
||||
#ifndef VS1053_DCS
|
||||
#define VS1053_DCS 25
|
||||
#endif
|
||||
#ifndef VS1053_DREQ
|
||||
#define VS1053_DREQ 26
|
||||
#endif
|
||||
#ifndef VS1053_RST
|
||||
#define VS1053_RST -1 // set to -1 if connected to Esp EN pin
|
||||
#endif
|
||||
|
||||
/* I2S DAC */
|
||||
#ifndef I2S_DOUT
|
||||
#define I2S_DOUT 27 // DIN connection
|
||||
#endif
|
||||
#ifndef I2S_BCLK
|
||||
#define I2S_BCLK 26 // BCLK Bit clock
|
||||
#endif
|
||||
#ifndef I2S_LRC
|
||||
#define I2S_LRC 25 // WSEL Left Right Clock
|
||||
#endif
|
||||
|
||||
/* ENCODER */
|
||||
#ifndef ENC_BTNL
|
||||
#define ENC_BTNL 255
|
||||
#endif
|
||||
#ifndef ENC_BTNB
|
||||
#define ENC_BTNB 255
|
||||
#endif
|
||||
#ifndef ENC_BTNR
|
||||
#define ENC_BTNR 255
|
||||
#endif
|
||||
#ifndef ENC_INTERNALPULLUP // Thanks for Buska1968. See this topic: https://4pda.to/forum/index.php?s=&showtopic=1010378&view=findpost&p=113385448
|
||||
#define ENC_INTERNALPULLUP true
|
||||
#endif
|
||||
#ifndef ENC_HALFQUARD
|
||||
#define ENC_HALFQUARD false
|
||||
#endif
|
||||
|
||||
#ifndef ENC2_BTNL
|
||||
#define ENC2_BTNL 255
|
||||
#endif
|
||||
#ifndef ENC2_BTNB
|
||||
#define ENC2_BTNB 255
|
||||
#endif
|
||||
#ifndef ENC2_BTNR
|
||||
#define ENC2_BTNR 255
|
||||
#endif
|
||||
#ifndef ENC2_INTERNALPULLUP
|
||||
#define ENC2_INTERNALPULLUP true
|
||||
#endif
|
||||
#ifndef ENC2_HALFQUARD
|
||||
#define ENC2_HALFQUARD false
|
||||
#endif
|
||||
|
||||
/* BUTTONS */
|
||||
#ifndef BTN_LEFT
|
||||
#define BTN_LEFT 255
|
||||
#endif
|
||||
#ifndef BTN_CENTER
|
||||
#define BTN_CENTER 255
|
||||
#endif
|
||||
#ifndef BTN_RIGHT
|
||||
#define BTN_RIGHT 255
|
||||
#endif
|
||||
#ifndef BTN_UP
|
||||
#define BTN_UP 255
|
||||
#endif
|
||||
#ifndef BTN_DOWN
|
||||
#define BTN_DOWN 255
|
||||
#endif
|
||||
#ifndef BTN_INTERNALPULLUP
|
||||
#define BTN_INTERNALPULLUP true
|
||||
#endif
|
||||
#ifndef BTN_LONGPRESS_LOOP_DELAY
|
||||
#define BTN_LONGPRESS_LOOP_DELAY 200 // delay between calling DuringLongPress event
|
||||
#endif
|
||||
#ifndef BTN_CLICK_TICKS
|
||||
#define BTN_CLICK_TICKS 300
|
||||
#endif
|
||||
#ifndef BTN_PRESS_TICKS
|
||||
#define BTN_PRESS_TICKS 500
|
||||
#endif
|
||||
|
||||
/* TOUCH SCREEN */
|
||||
#ifndef TS_CS
|
||||
#define TS_CS 255
|
||||
#endif
|
||||
|
||||
/* LCD DISPLAY */
|
||||
#ifndef LCD_RS
|
||||
#define LCD_RS 255
|
||||
#endif
|
||||
#ifndef LCD_E
|
||||
#define LCD_E 255
|
||||
#endif
|
||||
#ifndef LCD_D4
|
||||
#define LCD_D4 255
|
||||
#endif
|
||||
#ifndef LCD_D5
|
||||
#define LCD_D5 255
|
||||
#endif
|
||||
#ifndef LCD_D6
|
||||
#define LCD_D6 255
|
||||
#endif
|
||||
#ifndef LCD_D7
|
||||
#define LCD_D7 255
|
||||
#endif
|
||||
|
||||
/* ESP DEVBOARD */
|
||||
#ifndef LED_BUILTIN
|
||||
#define LED_BUILTIN 2
|
||||
#endif
|
||||
|
||||
/* Other settings. You can overwrite them in the myoptions.h file */
|
||||
#ifndef MUTE_PIN
|
||||
#define MUTE_PIN 255 // MUTE Pin
|
||||
#endif
|
||||
#ifndef MUTE_VAL
|
||||
#define MUTE_VAL HIGH // Write this to MUTE_PIN when player is stopped
|
||||
#endif
|
||||
#ifndef BRIGHTNESS_PIN
|
||||
#define BRIGHTNESS_PIN 255 // BRIGHTNESS Pin
|
||||
#endif
|
||||
#ifndef PLAYER_FORCE_MONO
|
||||
#define PLAYER_FORCE_MONO false // mono option - false stereo, true mono
|
||||
#endif
|
||||
#ifndef I2S_INTERNAL
|
||||
#define I2S_INTERNAL false // If true - use esp32 internal DAC
|
||||
#endif
|
||||
#ifndef ROTATE_90
|
||||
#define ROTATE_90 false // Optional 90 degree rotation for square displays
|
||||
#endif
|
||||
#ifndef WAKE_PIN
|
||||
#define WAKE_PIN 255 // Wake Pin (for manual wakeup from sleep mode. can match with BTN_XXXX, ENC_BTNB, ENC2_BTNB. must be one of: 0,2,4,12,13,14,15,25,26,27,32,33,34,35,36,39)
|
||||
#endif
|
||||
/*
|
||||
*** ST7735 display submodel ***
|
||||
INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html
|
||||
See this note If INITR_BLACKTAB have a noisy line on one side of the screen https://github.com/e2002/yoradio#note-if-initr_blacktab-dsp-have-a-noisy-line-on-one-side-of-the-screen-then-in-adafruit_st7735cpp
|
||||
INITR_144GREENTAB // 1.44' https://aliexpress.ru/item/1005002822797745.html
|
||||
INITR_MINI160x80 // 0.96' 160x80 ST7735S https://????
|
||||
INITR_GREENTAB
|
||||
INITR_REDTAB
|
||||
*/
|
||||
#ifndef DTYPE
|
||||
#define DTYPE INITR_BLACKTAB
|
||||
#endif
|
||||
|
||||
/* IR */
|
||||
#ifndef IR_PIN
|
||||
#define IR_PIN 255
|
||||
#endif
|
||||
#ifndef IR_TIMEOUT
|
||||
#define IR_TIMEOUT 80 // kTimeout, see IRremoteESP8266 documentation
|
||||
#endif
|
||||
|
||||
/* THEMES */
|
||||
/* color name R G B */
|
||||
#ifndef COLOR_BACKGROUND
|
||||
#define COLOR_BACKGROUND 0, 0, 0
|
||||
#endif
|
||||
#ifndef COLOR_STATION_NAME
|
||||
#define COLOR_STATION_NAME 0, 0, 0
|
||||
#endif
|
||||
#ifndef COLOR_STATION_BG
|
||||
#define COLOR_STATION_BG 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_STATION_FILL
|
||||
#define COLOR_STATION_FILL 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_SNG_TITLE_1
|
||||
#define COLOR_SNG_TITLE_1 255, 255, 255
|
||||
#endif
|
||||
#ifndef COLOR_SNG_TITLE_2
|
||||
#define COLOR_SNG_TITLE_2 165, 162, 132
|
||||
#endif
|
||||
#ifndef COLOR_WEATHER
|
||||
#define COLOR_WEATHER 255, 150, 0
|
||||
#endif
|
||||
#ifndef COLOR_VU_MAX
|
||||
#define COLOR_VU_MAX 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_VU_MIN
|
||||
#define COLOR_VU_MIN 123, 125, 123
|
||||
#endif
|
||||
#ifndef COLOR_CLOCK
|
||||
#define COLOR_CLOCK 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_SECONDS
|
||||
#define COLOR_SECONDS 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_DAY_OF_W
|
||||
#define COLOR_DAY_OF_W 255, 255, 255
|
||||
#endif
|
||||
#ifndef COLOR_DATE
|
||||
#define COLOR_DATE 255, 255, 255
|
||||
#endif
|
||||
#ifndef COLOR_HEAP
|
||||
#define COLOR_HEAP 41, 40, 41
|
||||
#endif
|
||||
#ifndef COLOR_BUFFER
|
||||
#define COLOR_BUFFER 165, 162, 132
|
||||
#endif
|
||||
#ifndef COLOR_IP
|
||||
#define COLOR_IP 165, 162, 132
|
||||
#endif
|
||||
#ifndef COLOR_VOLUME_VALUE
|
||||
#define COLOR_VOLUME_VALUE 165, 162, 132
|
||||
#endif
|
||||
#ifndef COLOR_RSSI
|
||||
#define COLOR_RSSI 165, 162, 132
|
||||
#endif
|
||||
#ifndef COLOR_VOLBAR_OUT
|
||||
#define COLOR_VOLBAR_OUT 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_VOLBAR_IN
|
||||
#define COLOR_VOLBAR_IN 231, 211, 90
|
||||
#endif
|
||||
#ifndef COLOR_DIGITS
|
||||
#define COLOR_DIGITS 255, 255, 255
|
||||
#endif
|
||||
#ifndef COLOR_DIVIDER
|
||||
#define COLOR_DIVIDER 165, 162, 132
|
||||
#endif
|
||||
#ifndef COLOR_PLAYLIST_0
|
||||
#define COLOR_PLAYLIST_0 115, 115, 115
|
||||
#endif
|
||||
#ifndef COLOR_PLAYLIST_1
|
||||
#define COLOR_PLAYLIST_1 89, 89, 89
|
||||
#endif
|
||||
#ifndef COLOR_PLAYLIST_2
|
||||
#define COLOR_PLAYLIST_2 56, 56, 56
|
||||
#endif
|
||||
#ifndef COLOR_PLAYLIST_3
|
||||
#define COLOR_PLAYLIST_3 35, 35, 35
|
||||
#endif
|
||||
#ifndef COLOR_PLAYLIST_4
|
||||
#define COLOR_PLAYLIST_4 25, 25, 25
|
||||
#endif
|
||||
#ifndef COLOR_BITRATE
|
||||
#define COLOR_BITRATE 231, 211, 90
|
||||
#endif
|
||||
|
||||
#define EN 1
|
||||
#define RU 2
|
||||
#ifndef L10N_LANGUAGE
|
||||
#define L10N_LANGUAGE EN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
200
yoRadio/src/core/player.cpp
Normal file
200
yoRadio/src/core/player.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "options.h"
|
||||
|
||||
#include "player.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "telnet.h"
|
||||
#include "display.h"
|
||||
|
||||
#include "netserver.h"
|
||||
|
||||
Player player;
|
||||
|
||||
#if VS1053_CS!=255 && !I2S_INTERNAL
|
||||
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ) {
|
||||
|
||||
}
|
||||
void ResetChip(){
|
||||
pinMode(VS1053_RST, OUTPUT);
|
||||
digitalWrite(VS1053_RST, LOW);
|
||||
delay(30);
|
||||
digitalWrite(VS1053_RST, HIGH);
|
||||
delay(100);
|
||||
}
|
||||
#else
|
||||
#if !I2S_INTERNAL
|
||||
Player::Player() {}
|
||||
#else
|
||||
Player::Player(): Audio(true, I2S_DAC_CHANNEL_BOTH_EN) {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
void Player::init() {
|
||||
if(MUTE_PIN!=255) pinMode(MUTE_PIN, OUTPUT);
|
||||
#if I2S_DOUT!=255
|
||||
#if !I2S_INTERNAL
|
||||
setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
#endif
|
||||
#else
|
||||
SPI.begin();
|
||||
if(VS1053_RST>0) ResetChip();
|
||||
begin();
|
||||
#endif
|
||||
setBalance(config.store.balance);
|
||||
setTone(config.store.bass, config.store.middle, config.store.trebble);
|
||||
setVolume(0);
|
||||
mode = STOPPED;
|
||||
setOutputPins(false);
|
||||
requestToStart = true;
|
||||
volTimer=false;
|
||||
zeroRequest();
|
||||
playmutex = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
void Player::stopInfo() {
|
||||
config.setSmartStart(0);
|
||||
telnet.info();
|
||||
netserver.requestOnChange(MODE, 0);
|
||||
requestToStart = true;
|
||||
}
|
||||
|
||||
void Player::stop(const char *nttl){
|
||||
mode = STOPPED;
|
||||
setOutputPins(false);
|
||||
if(nttl) config.setTitle(nttl);
|
||||
else config.setTitle((display.mode()==LOST || display.mode()==UPDATING)?"":const_PlStopped);
|
||||
netserver.requestOnChange(TITLE, 0);
|
||||
config.station.bitrate = 0;
|
||||
#ifdef USE_NEXTION
|
||||
nextion.bitrate(config.station.bitrate);
|
||||
#endif
|
||||
netserver.requestOnChange(BITRATE, 0);
|
||||
display.putRequest(DBITRATE);
|
||||
display.putRequest(PSTOP);
|
||||
setDefaults();
|
||||
stopInfo();
|
||||
if (player_on_stop_play) player_on_stop_play();
|
||||
}
|
||||
|
||||
void Player::loop() {
|
||||
if (mode == PLAYING) {
|
||||
xSemaphoreTake(playmutex, portMAX_DELAY);
|
||||
Audio::loop();
|
||||
xSemaphoreGive(playmutex);
|
||||
} else {
|
||||
if (isRunning()) stop();
|
||||
}
|
||||
if (request.station > 0) {
|
||||
if (request.doSave) {
|
||||
config.setLastStation(request.station);
|
||||
}
|
||||
play(request.station);
|
||||
if (player_on_station_change) player_on_station_change();
|
||||
zeroRequest();
|
||||
}
|
||||
if (request.volume >= 0) {
|
||||
config.setVolume(request.volume);
|
||||
telnet.printf("##CLI.VOL#: %d\n", config.store.volume);
|
||||
Audio::setVolume(volToI2S(request.volume));
|
||||
zeroRequest();
|
||||
display.putRequest(DRAWVOL);
|
||||
netserver.requestOnChange(VOLUME, 0);
|
||||
}
|
||||
if(volTimer){
|
||||
if((millis()-volTicks)>3000){
|
||||
config.saveVolume();
|
||||
volTimer=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::zeroRequest() {
|
||||
request.station = 0;
|
||||
request.volume = -1;
|
||||
request.doSave = false;
|
||||
}
|
||||
|
||||
void Player::setOutputPins(bool isPlaying) {
|
||||
digitalWrite(LED_BUILTIN, isPlaying);
|
||||
if(MUTE_PIN!=255) digitalWrite(MUTE_PIN, isPlaying?!MUTE_VAL:MUTE_VAL);
|
||||
}
|
||||
|
||||
void Player::play(uint16_t stationId) {
|
||||
display.putRequest(PSTOP);
|
||||
setDefaults();
|
||||
setOutputPins(false);
|
||||
config.setTitle(const_PlConnect);
|
||||
config.station.bitrate=0;
|
||||
netserver.requestOnChange(TITLE, 0);
|
||||
config.loadStation(stationId);
|
||||
setVol(config.store.volume, true);
|
||||
display.putRequest(NEWSTATION);
|
||||
netserver.requestOnChange(STATION, 0);
|
||||
telnet.printf("##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name);
|
||||
if (connecttohost(config.station.url)) {
|
||||
mode = PLAYING;
|
||||
config.setSmartStart(1);
|
||||
netserver.requestOnChange(MODE, 0);
|
||||
setOutputPins(true);
|
||||
requestToStart = true;
|
||||
display.putRequest(PSTART);
|
||||
if (player_on_start_play) player_on_start_play();
|
||||
}else{
|
||||
Serial.println("some unknown bug...");
|
||||
};
|
||||
}
|
||||
|
||||
void Player::prev() {
|
||||
if (config.store.lastStation == 1) config.store.lastStation = config.store.countStation; else config.store.lastStation--;
|
||||
request.station = config.store.lastStation;
|
||||
request.doSave = true;
|
||||
}
|
||||
|
||||
void Player::next() {
|
||||
if (config.store.lastStation == config.store.countStation) config.store.lastStation = 1; else config.store.lastStation++;
|
||||
request.station = config.store.lastStation;
|
||||
request.doSave = true;
|
||||
}
|
||||
|
||||
void Player::toggle() {
|
||||
if (mode == PLAYING) {
|
||||
mode = STOPPED;
|
||||
} else {
|
||||
request.station = config.store.lastStation;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::stepVol(bool up) {
|
||||
if (up) {
|
||||
if (config.store.volume <= 254 - config.store.volsteps) {
|
||||
setVol(config.store.volume + config.store.volsteps, false);
|
||||
}else{
|
||||
setVol(254, false);
|
||||
}
|
||||
} else {
|
||||
if (config.store.volume >= config.store.volsteps) {
|
||||
setVol(config.store.volume - config.store.volsteps, false);
|
||||
}else{
|
||||
setVol(0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte Player::volToI2S(byte volume) {
|
||||
int vol = map(volume, 0, 254 - config.station.ovol * 3 , 0, 254);
|
||||
if (vol > 254) vol = 254;
|
||||
if (vol < 0) vol = 0;
|
||||
return vol;
|
||||
}
|
||||
|
||||
void Player::setVol(byte volume, bool inside) {
|
||||
if (inside) {
|
||||
setVolume(volToI2S(volume));
|
||||
} else {
|
||||
volTicks = millis();
|
||||
volTimer = true;
|
||||
request.volume = volume;
|
||||
request.doSave = true;
|
||||
}
|
||||
}
|
||||
51
yoRadio/src/core/player.h
Normal file
51
yoRadio/src/core/player.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef player_h
|
||||
#define player_h
|
||||
#include "options.h"
|
||||
|
||||
#if I2S_DOUT!=255 || I2S_INTERNAL
|
||||
#include "../audioI2S/AudioEx.h"
|
||||
#else
|
||||
#include "../audioVS1053/audioVS1053Ex.h"
|
||||
#endif
|
||||
|
||||
enum audioMode_e { PLAYING, STOPPED };
|
||||
struct audiorequest_t
|
||||
{
|
||||
uint16_t station;
|
||||
int volume;
|
||||
bool doSave;
|
||||
};
|
||||
class Player: public Audio {
|
||||
private:
|
||||
uint32_t volTicks; /* delayed volume save */
|
||||
bool volTimer; /* delayed volume save */
|
||||
public:
|
||||
audioMode_e mode;
|
||||
audiorequest_t request;
|
||||
bool requestToStart;
|
||||
void zeroRequest();
|
||||
SemaphoreHandle_t playmutex=NULL;
|
||||
public:
|
||||
Player();
|
||||
void init();
|
||||
void loop();
|
||||
void play(uint16_t stationId);
|
||||
void stop(const char *nttl = NULL);
|
||||
void prev();
|
||||
void next();
|
||||
void toggle();
|
||||
void stepVol(bool up);
|
||||
void setVol(byte volume, bool inside);
|
||||
byte volToI2S(byte volume);
|
||||
void stopInfo();
|
||||
void setOutputPins(bool isPlaying);
|
||||
};
|
||||
|
||||
extern Player player;
|
||||
|
||||
extern __attribute__((weak)) void player_on_start_play();
|
||||
extern __attribute__((weak)) void player_on_stop_play();
|
||||
extern __attribute__((weak)) void player_on_track_change();
|
||||
extern __attribute__((weak)) void player_on_station_change();
|
||||
|
||||
#endif
|
||||
460
yoRadio/src/core/telnet.cpp
Normal file
460
yoRadio/src/core/telnet.cpp
Normal file
@@ -0,0 +1,460 @@
|
||||
#include <stdarg.h>
|
||||
#include "WiFi.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "player.h"
|
||||
#include "network.h"
|
||||
#include "telnet.h"
|
||||
|
||||
Telnet telnet;
|
||||
|
||||
bool Telnet::_isIPSet(IPAddress ip) {
|
||||
return ip.toString() == "0.0.0.0";
|
||||
}
|
||||
|
||||
bool Telnet::begin() {
|
||||
if (WiFi.status() == WL_CONNECTED || _isIPSet(WiFi.softAPIP())) {
|
||||
server.begin();
|
||||
server.setNoDelay(true);
|
||||
Serial.printf("Ready! Use 'telnet %s 23' to connect\n", WiFi.localIP().toString().c_str());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet::stop() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
void Telnet::emptyClientStream(WiFiClient client) {
|
||||
client.flush();
|
||||
delay(50);
|
||||
while (client.available()) {
|
||||
client.read();
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet::cleanupClients() {
|
||||
for (int i = 0; i < MAX_TLN_CLIENTS; i++) {
|
||||
if (!clients[i].connected()) {
|
||||
if (clients[i]) {
|
||||
Serial.printf("Client [%d] is %s\n", i, clients[i].connected() ? "connected" : "disconnected");
|
||||
clients[i].stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet::handleSerial(){
|
||||
if(Serial.available()){
|
||||
String request = Serial.readStringUntil('\n'); request.trim();
|
||||
on_input(request.c_str(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet::loop() {
|
||||
uint8_t i;
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (server.hasClient()) {
|
||||
for (i = 0; i < MAX_TLN_CLIENTS; i++) {
|
||||
if (!clients[i] || !clients[i].connected()) {
|
||||
if (clients[i]) {
|
||||
clients[i].stop();
|
||||
}
|
||||
clients[i] = server.available();
|
||||
if (!clients[i]) Serial.println("available broken");
|
||||
on_connect(clients[i].remoteIP().toString().c_str(), i);
|
||||
clients[i].setNoDelay(true);
|
||||
emptyClientStream(clients[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= MAX_TLN_CLIENTS) {
|
||||
server.available().stop();
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_TLN_CLIENTS; i++) {
|
||||
if (clients[i] && clients[i].connected() && clients[i].available()) {
|
||||
String inputstr = clients[i].readStringUntil('\n');
|
||||
inputstr.trim();
|
||||
on_input(inputstr.c_str(), i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < MAX_TLN_CLIENTS; i++) {
|
||||
if (clients[i]) {
|
||||
clients[i].stop();
|
||||
}
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
handleSerial();
|
||||
yield();
|
||||
}
|
||||
|
||||
void Telnet::print(const char *buf) {
|
||||
for (int id = 0; id < MAX_TLN_CLIENTS; id++) {
|
||||
if (clients[id] && clients[id].connected()) {
|
||||
print(id, buf);
|
||||
}
|
||||
}
|
||||
Serial.print(buf);
|
||||
}
|
||||
|
||||
void Telnet::print(byte id, const char *buf) {
|
||||
if (clients[id] && clients[id].connected()) {
|
||||
clients[id].print(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet::printf(const char *format, ...) {
|
||||
char buf[MAX_PRINTF_LEN];
|
||||
va_list args;
|
||||
va_start (args, format );
|
||||
vsnprintf(buf, MAX_PRINTF_LEN, format, args);
|
||||
va_end (args);
|
||||
for (int id = 0; id < MAX_TLN_CLIENTS; id++) {
|
||||
if (clients[id] && clients[id].connected()) {
|
||||
clients[id].print(buf);
|
||||
}
|
||||
}
|
||||
Serial.print(buf);
|
||||
}
|
||||
|
||||
/*void Telnet::printf(byte id, const char *format, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
char *szBuffer = 0;
|
||||
const size_t nBufferLength = vsnprintf(szBuffer, 0, format, argptr) + 1;
|
||||
if (nBufferLength == 1) return;
|
||||
szBuffer = (char *) malloc(nBufferLength);
|
||||
if (! szBuffer) return;
|
||||
vsnprintf(szBuffer, nBufferLength, format, argptr);
|
||||
va_end(argptr);
|
||||
if(id>MAX_TLN_CLIENTS){
|
||||
Serial.print(szBuffer);
|
||||
free(szBuffer);
|
||||
return;
|
||||
}
|
||||
if (clients[id] && clients[id].connected()) {
|
||||
clients[id].print(szBuffer);
|
||||
free(szBuffer);
|
||||
}
|
||||
}*/
|
||||
|
||||
void Telnet::printf(byte id, const char *format, ...) {
|
||||
char buf[MAX_PRINTF_LEN];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsnprintf(buf, MAX_PRINTF_LEN, format, argptr);
|
||||
va_end(argptr);
|
||||
if(id>MAX_TLN_CLIENTS){
|
||||
Serial.print(buf);
|
||||
return;
|
||||
}
|
||||
if (clients[id] && clients[id].connected()) {
|
||||
clients[id].print(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet::on_connect(const char* str, byte clientId) {
|
||||
Serial.printf("Telnet: [%d] %s connected\n", clientId, str);
|
||||
print(clientId, "\nWelcome to ёRadio!\n(Use ^] + q to disconnect.)\n> ");
|
||||
}
|
||||
|
||||
void Telnet::info() {
|
||||
telnet.printf("##CLI.INFO#\n");
|
||||
char timeStringBuff[50];
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &network.timeinfo);
|
||||
telnet.printf("##SYS.DATE#: %s\n", timeStringBuff); //TODO timezone offset
|
||||
telnet.printf("##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name);
|
||||
if (player.mode == PLAYING) {
|
||||
telnet.printf("##CLI.META#: %s\n", config.station.title);
|
||||
}
|
||||
telnet.printf("##CLI.VOL#: %d\n", config.store.volume);
|
||||
if (player.mode == PLAYING) {
|
||||
telnet.printf("##CLI.PLAYING#\n");
|
||||
} else {
|
||||
telnet.printf("##CLI.STOPPED#\n");
|
||||
}
|
||||
telnet.printf("> ");
|
||||
}
|
||||
|
||||
void Telnet::on_input(const char* str, byte clientId) {
|
||||
if (strlen(str) == 0) return;
|
||||
if(network.status == CONNECTED){
|
||||
if (strcmp(str, "cli.prev") == 0 || strcmp(str, "prev") == 0) {
|
||||
player.prev();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.next") == 0 || strcmp(str, "next") == 0) {
|
||||
player.next();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.toggle") == 0 || strcmp(str, "toggle") == 0) {
|
||||
player.toggle();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.stop") == 0 || strcmp(str, "stop") == 0) {
|
||||
player.mode = STOPPED;
|
||||
//display.title("[stopped]");
|
||||
info();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.start") == 0 || strcmp(str, "start") == 0 || strcmp(str, "cli.play") == 0 || strcmp(str, "play") == 0) {
|
||||
player.play(config.store.lastStation);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.vol") == 0 || strcmp(str, "vol") == 0) {
|
||||
printf(clientId, "##CLI.VOL#: %d\n> ", config.store.volume);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.vol-") == 0 || strcmp(str, "vol-") == 0) {
|
||||
player.stepVol(false);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.vol+") == 0 || strcmp(str, "vol+") == 0) {
|
||||
player.stepVol(true);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "sys.date") == 0 || strcmp(str, "date") == 0 || strcmp(str, "time") == 0) {
|
||||
network.requestTimeSync(true, clientId > MAX_TLN_CLIENTS?clientId:0);
|
||||
return;
|
||||
}
|
||||
int volume;
|
||||
if (sscanf(str, "vol(%d)", &volume) == 1 || sscanf(str, "cli.vol(\"%d\")", &volume) == 1 || sscanf(str, "vol %d", &volume) == 1) {
|
||||
if (volume < 0) volume = 0;
|
||||
if (volume > 254) volume = 254;
|
||||
player.setVol(volume, false);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.audioinfo") == 0 || strcmp(str, "audioinfo") == 0) {
|
||||
printf(clientId, "##CLI.AUDIOINFO#: %d\n> ", config.store.audioinfo > 0);
|
||||
return;
|
||||
}
|
||||
int ainfo;
|
||||
if (sscanf(str, "audioinfo(%d)", &ainfo) == 1 || sscanf(str, "cli.audioinfo(\"%d\")", &ainfo) == 1 || sscanf(str, "audioinfo %d", &ainfo) == 1) {
|
||||
config.store.audioinfo = ainfo > 0;
|
||||
printf(clientId, "new audioinfo value is: %d\n> ", config.store.audioinfo);
|
||||
config.save();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.smartstart") == 0 || strcmp(str, "smartstart") == 0) {
|
||||
printf(clientId, "##CLI.SMARTSTART#: %d\n> ", config.store.smartstart);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
printf(clientId, "new smartstart value is: %d\n> ", config.store.smartstart);
|
||||
config.save();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.list") == 0 || strcmp(str, "list") == 0) {
|
||||
printf(clientId, "#CLI.LIST#\n");
|
||||
File file = SPIFFS.open(PLAYLIST_PATH, "r");
|
||||
if (!file || file.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
char sName[BUFLEN], sUrl[BUFLEN];
|
||||
int sOvol;
|
||||
byte 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);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
printf(clientId, "##CLI.LIST#\n");
|
||||
printf(clientId, "> ");
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "cli.info") == 0 || strcmp(str, "info") == 0) {
|
||||
printf(clientId, "##CLI.INFO#\n");
|
||||
char timeStringBuff[50];
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &network.timeinfo);
|
||||
if (config.store.tzHour < 0) {
|
||||
printf(clientId, "##SYS.DATE#: %s%03d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin);
|
||||
} else {
|
||||
printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin);
|
||||
}
|
||||
printf(clientId, "##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name);
|
||||
if (player.mode == PLAYING) {
|
||||
printf(clientId, "##CLI.META#: %s\n", config.station.title);
|
||||
}
|
||||
printf(clientId, "##CLI.VOL#: %d\n", config.store.volume);
|
||||
if (player.mode == PLAYING) {
|
||||
printf(clientId, "##CLI.PLAYING#\n");
|
||||
} else {
|
||||
printf(clientId, "##CLI.STOPPED#\n");
|
||||
}
|
||||
printf(clientId, "> ");
|
||||
return;
|
||||
}
|
||||
int sb;
|
||||
if (sscanf(str, "play(%d)", &sb) == 1 || sscanf(str, "cli.play(\"%d\")", &sb) == 1 || sscanf(str, "play %d", &sb) == 1 ) {
|
||||
if (sb < 1) sb = 1;
|
||||
if (sb >= config.store.countStation) sb = config.store.countStation;
|
||||
player.play((uint16_t)sb);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "sys.tzo") == 0 || strcmp(str, "tzo") == 0) {
|
||||
printf(clientId, "##SYS.TZO#: %d:%d\n> ", config.store.tzHour, config.store.tzMin);
|
||||
return;
|
||||
}
|
||||
//int16_t tzh, tzm;
|
||||
int tzh, tzm;
|
||||
if (sscanf(str, "tzo(%d:%d)", &tzh, &tzm) == 2 || sscanf(str, "sys.tzo(\"%d:%d\")", &tzh, &tzm) == 2 || sscanf(str, "tzo %d:%d", &tzh, &tzm) == 2) {
|
||||
if (tzh < -12) tzh = -12;
|
||||
if (tzh > 14) tzh = 14;
|
||||
if (tzm < 0) tzm = 0;
|
||||
if (tzm > 59) tzm = 59;
|
||||
config.setTimezone((int8_t)tzh, (int8_t)tzm);
|
||||
if(tzh<0){
|
||||
printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin);
|
||||
}else{
|
||||
printf(clientId, "new timezone offset: %02d:%02d\n", config.store.tzHour, config.store.tzMin);
|
||||
}
|
||||
network.requestTimeSync(true);
|
||||
return;
|
||||
}
|
||||
if (sscanf(str, "tzo(%d)", &tzh) == 1 || sscanf(str, "sys.tzo(\"%d\")", &tzh) == 1 || sscanf(str, "tzo %d", &tzh) == 1) {
|
||||
if (tzh < -12) tzh = -12;
|
||||
if (tzh > 14) tzh = 14;
|
||||
config.setTimezone((int8_t)tzh, 0);
|
||||
if(tzh<0){
|
||||
printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin);
|
||||
}else{
|
||||
printf(clientId, "new timezone offset: %02d:%02d\n", config.store.tzHour, config.store.tzMin);
|
||||
}
|
||||
network.requestTimeSync(true);
|
||||
return;
|
||||
}
|
||||
if (sscanf(str, "dspon(%d)", &tzh) == 1 || sscanf(str, "cli.dspon(\"%d\")", &tzh) == 1 || sscanf(str, "dspon %d", &tzh) == 1) {
|
||||
config.setDspOn(tzh!=0);
|
||||
return;
|
||||
}
|
||||
if (sscanf(str, "dim(%d)", &tzh) == 1 || sscanf(str, "cli.dim(\"%d\")", &tzh) == 1 || sscanf(str, "dim %d", &tzh) == 1) {
|
||||
if (tzh < 0) tzh = 0;
|
||||
if (tzh > 100) tzh = 100;
|
||||
config.store.brightness = (uint8_t)tzh;
|
||||
config.setBrightness(true);
|
||||
return;
|
||||
}
|
||||
if (sscanf(str, "sleep(%d,%d)", &tzh, &tzm) == 2 || sscanf(str, "cli.sleep(\"%d\",\"%d\")", &tzh, &tzm) == 2 || sscanf(str, "sleep %d %d", &tzh, &tzm) == 2) {
|
||||
if(tzh>0 && tzm>0) {
|
||||
printf(clientId, "sleep for %d minutes after %d minutes ...\n> ", tzh, tzm);
|
||||
config.sleepForAfter(tzh, tzm);
|
||||
}else{
|
||||
printf(clientId, "##CMD_ERROR#\tunknown command <%s>\n> ", str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (sscanf(str, "sleep(%d)", &tzh) == 1 || sscanf(str, "cli.sleep(\"%d\")", &tzh) == 1 || sscanf(str, "sleep %d", &tzh) == 1) {
|
||||
if(tzh>0) {
|
||||
printf(clientId, "sleep for %d minutes ...\n> ", tzh);
|
||||
config.sleepForAfter(tzh);
|
||||
}else{
|
||||
printf(clientId, "##CMD_ERROR#\tunknown command <%s>\n> ", str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strcmp(str, "sys.version") == 0 || strcmp(str, "version") == 0) {
|
||||
printf(clientId, "##SYS.VERSION#: %s\n> ", VERSION);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "sys.boot") == 0 || strcmp(str, "boot") == 0 || strcmp(str, "reboot") == 0) {
|
||||
ESP.restart();
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "wifi.list") == 0 || strcmp(str, "wifi") == 0) {
|
||||
printf(clientId, "#WIFI.SCAN#\n");
|
||||
int n = WiFi.scanNetworks();
|
||||
if (n == 0) {
|
||||
printf(clientId, "no networks found\n");
|
||||
} else {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
printf(clientId, "%d", i + 1);
|
||||
printf(clientId, ": ");
|
||||
printf(clientId, "%s", WiFi.SSID(i));
|
||||
printf(clientId, " (");
|
||||
printf(clientId, "%d", WiFi.RSSI(i));
|
||||
printf(clientId, ")");
|
||||
printf(clientId, (WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
|
||||
printf(clientId, "\n");
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
printf(clientId, "#WIFI.SCAN#\n> ");
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "wifi.con") == 0 || strcmp(str, "conn") == 0) {
|
||||
printf(clientId, "#WIFI.CON#\n");
|
||||
File file = SPIFFS.open(SSIDS_PATH, "r");
|
||||
if (file && !file.isDirectory()) {
|
||||
char sSid[BUFLEN], sPas[BUFLEN];
|
||||
byte c = 1;
|
||||
while (file.available()) {
|
||||
if (config.parseSsid(file.readStringUntil('\n').c_str(), sSid, sPas)) {
|
||||
printf(clientId, "%d: %s, %s\n", c, sSid, sPas);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(clientId, "##WIFI.CON#\n> ");
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "wifi.station") == 0 || strcmp(str, "station") == 0 || strcmp(str, "ssid") == 0) {
|
||||
printf(clientId, "#WIFI.STATION#\n");
|
||||
File file = SPIFFS.open(SSIDS_PATH, "r");
|
||||
if (file && !file.isDirectory()) {
|
||||
char sSid[BUFLEN], sPas[BUFLEN];
|
||||
byte 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);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(clientId, "##WIFI.STATION#\n> ");
|
||||
return;
|
||||
}
|
||||
char newssid[20], newpass[40];
|
||||
if (sscanf(str, "wifi.con(\"%[^\"]\",\"%[^\"]\")", newssid, newpass) == 2 || sscanf(str, "wifi.con(%[^,],%[^)])", newssid, newpass) == 2 || sscanf(str, "wifi.con(%[^ ] %[^)])", newssid, newpass) == 2 || sscanf(str, "wifi %[^ ] %s", newssid, newpass) == 2) {
|
||||
char buf[BUFLEN];
|
||||
snprintf(buf, BUFLEN, "New SSID: \"%s\" with PASS: \"%s\" for next boot\n> ", newssid, newpass);
|
||||
printf(clientId, buf);
|
||||
printf(clientId, "...REBOOTING...\n> ");
|
||||
memset(buf, 0, BUFLEN);
|
||||
snprintf(buf, BUFLEN, "%s\t%s", newssid, newpass);
|
||||
config.saveWifiFromNextion(buf);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "wifi.status") == 0 || strcmp(str, "status") == 0) {
|
||||
printf(clientId, "#WIFI.STATUS#\nStatus:\t\t%d\nMode:\t\t%s\nIP:\t\t%s\nMask:\t\t%s\nGateway:\t%s\nRSSI:\t\t%d dBm\n##WIFI.STATUS#\n> ",
|
||||
WiFi.status(), WiFi.getMode()==WIFI_STA?"WIFI_STA":"WIFI_AP",
|
||||
WiFi.getMode()==WIFI_STA?WiFi.localIP().toString():WiFi.softAPIP().toString(),
|
||||
WiFi.getMode()==WIFI_STA?WiFi.subnetMask().toString():"255.255.255.0",
|
||||
WiFi.getMode()==WIFI_STA?WiFi.gatewayIP().toString():WiFi.softAPIP().toString(),
|
||||
WiFi.RSSI()
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "wifi.rssi") == 0 || strcmp(str, "rssi") == 0) {
|
||||
printf(clientId, "#WIFI.RSSI#\t%d dBm\n> ", WiFi.RSSI());
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "sys.heap") == 0 || strcmp(str, "heap") == 0) {
|
||||
printf(clientId, "Free heap:\t%d bytes\n> ", xPortGetFreeHeapSize());
|
||||
return;
|
||||
}
|
||||
if (strcmp(str, "wifi.discon") == 0 || strcmp(str, "discon") == 0 || strcmp(str, "disconnect") == 0) {
|
||||
printf(clientId, "#WIFI.DISCON#\tdisconnected...\n> ");
|
||||
WiFi.disconnect();
|
||||
return;
|
||||
}
|
||||
telnet.printf(clientId, "##CMD_ERROR#\tunknown command <%s>\n> ", str);
|
||||
}
|
||||
34
yoRadio/src/core/telnet.h
Normal file
34
yoRadio/src/core/telnet.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef telnet_h
|
||||
#define telnet_h
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#define MAX_TLN_CLIENTS 5
|
||||
#define MAX_PRINTF_LEN BUFLEN+50
|
||||
|
||||
class Telnet {
|
||||
public:
|
||||
Telnet() {};
|
||||
bool begin();
|
||||
void loop();
|
||||
void stop();
|
||||
void print(byte id, const char *buf);
|
||||
void print(const char *buf);
|
||||
void printf(byte id, const char *format, ...);
|
||||
void printf(const char *format, ...);
|
||||
void cleanupClients();
|
||||
void info();
|
||||
protected:
|
||||
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);
|
||||
private:
|
||||
bool _isIPSet(IPAddress ip);
|
||||
void handleSerial();
|
||||
};
|
||||
|
||||
extern Telnet telnet;
|
||||
|
||||
#endif
|
||||
71
yoRadio/src/displays/conf/displayGC9106conf.h
Normal file
71
yoRadio/src/displays/conf/displayGC9106conf.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************************
|
||||
GC9106 160x80 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayGC9106conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayGC9106conf_h
|
||||
#define displayGC9106conf_h
|
||||
|
||||
#define DSP_WIDTH 160
|
||||
#define TFT_FRAMEWDT 1
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 19
|
||||
|
||||
#define HIDE_IP
|
||||
#define HIDE_TITLE2
|
||||
#define HIDE_VOL
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 19, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-4, 5000, 3, 30 };
|
||||
//const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 36, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 2, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 33, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 80-TFT_FRAMEWDT-8, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 80-13, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-4, 0, 3, 30 }; // ПОГОДА!!
|
||||
|
||||
/* BACKGROUNGC9106DS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 16, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 80-1-1-2, 0, WA_LEFT }, MAX_WIDTH, 2, false };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 30, 0, WA_LEFT }, DSP_WIDTH, 20, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 79, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 65, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 19, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
//const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 80-13, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 29+32, 35, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 20, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 32, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 46, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 58, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 29+34, 35, WA_RIGHT }; /* 35 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { 1, 28, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 50, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 48, 2, 1, 8, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
//const char iptxtFmt[] PROGMEM = "%s";
|
||||
//const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 14, 29+34, 0};
|
||||
const MoveConfig weatherMove PROGMEM = { TFT_FRAMEWDT, 80-13, MAX_WIDTH-6*3-4-30 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 30, 80-13, MAX_WIDTH-6*3-4-30 };
|
||||
|
||||
#endif
|
||||
67
yoRadio/src/displays/conf/displayILI9225conf.h
Normal file
67
yoRadio/src/displays/conf/displayILI9225conf.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*************************************************************************************
|
||||
ILI9225 220x176 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayILI9225conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayILI9225conf_h
|
||||
#define displayILI9225conf_h
|
||||
|
||||
#define DSP_WIDTH 220
|
||||
#define DSP_HEIGHT 176
|
||||
#define TFT_FRAMEWDT 4
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 9
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
|
||||
#define bootLogoTop 28
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, DSP_WIDTH+10, 5000, 4, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 28, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 3, 25 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 40, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 3, 25 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 80, 2, WA_LEFT }, 140, true, DSP_WIDTH+10, 1000, 4, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, DSP_HEIGHT-TFT_FRAMEWDT-16, 2, WA_LEFT }, 140, false, DSP_WIDTH+10, 0, 3, 25 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 50, 2, WA_LEFT }, 140, true, DSP_WIDTH+10, 0, 4, 30 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, DSP_HEIGHT-TFT_FRAMEWDT-4, 0, WA_LEFT }, MAX_WIDTH, 4, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 76, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, DSP_HEIGHT-1, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 150, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT+6, DSP_HEIGHT-TFT_FRAMEWDT-14-14, 1, WA_RIGHT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 80, DSP_HEIGHT-TFT_FRAMEWDT-14, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, DSP_HEIGHT-TFT_FRAMEWDT-14, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, DSP_HEIGHT-TFT_FRAMEWDT-14, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 110, 35, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { TFT_FRAMEWDT, 38, 2, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { TFT_FRAMEWDT, 62, 2, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { TFT_FRAMEWDT, 102, 2, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { TFT_FRAMEWDT, 126, 2, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 12, 120, 35, WA_RIGHT }; /* 35 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 58, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 130, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 19, 90, 2, 2, 10, 4 };
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "WiFi %d";
|
||||
const char iptxtFmt[] PROGMEM = "IP %s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d kBs";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 2, 120, 0 };
|
||||
const MoveConfig weatherMove PROGMEM = { TFT_FRAMEWDT, 58, DSP_WIDTH+10 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { TFT_FRAMEWDT+46, 58, DSP_WIDTH+10-46 };
|
||||
|
||||
#endif
|
||||
67
yoRadio/src/displays/conf/displayILI9341conf.h
Normal file
67
yoRadio/src/displays/conf/displayILI9341conf.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*************************************************************************************
|
||||
ILI9341 320x240 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayILI9341conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayILI9341conf_h
|
||||
#define displayILI9341conf_h
|
||||
|
||||
#define DSP_WIDTH 320
|
||||
#define TFT_FRAMEWDT 8
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 11
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 3, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 5, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 50, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 70, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 112, 2, WA_LEFT }, 140, true, MAX_WIDTH, 1000, 4, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 3, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 20 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 240-TFT_FRAMEWDT-16, 2, WA_LEFT }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ 8, 87, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 4, 30 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 38, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 240-TFT_FRAMEWDT-6, 0, WA_LEFT }, MAX_WIDTH, 6, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 107, 0, WA_LEFT }, DSP_WIDTH, 24, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 239, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 182, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 70, 191, 1, WA_LEFT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 0, 214, 1, WA_CENTER };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 214, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 214, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 120+30, 52, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { TFT_FRAMEWDT, 66, 2, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { TFT_FRAMEWDT, 90, 2, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { TFT_FRAMEWDT, 130, 2, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { TFT_FRAMEWDT, 154, 2, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 12, 176, 52, WA_RIGHT }; /* 52 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 100, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 162, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 24, 100, 4, 2, 10, 5 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "WiFi %d";
|
||||
const char iptxtFmt[] PROGMEM = "IP %s";
|
||||
const char voltxtFmt[] PROGMEM = "vol %d";
|
||||
const char bitrateFmt[] PROGMEM = "%d kBs";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 176, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 8, 97, MAX_WIDTH };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 70, 97, 250 };
|
||||
|
||||
#endif
|
||||
52
yoRadio/src/displays/conf/displayLCD1602conf.h
Normal file
52
yoRadio/src/displays/conf/displayLCD1602conf.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*************************************************************************************
|
||||
LCD1602 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayLCD1602conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayLCD1602conf_h
|
||||
#define displayLCD1602conf_h
|
||||
|
||||
#define DSP_WIDTH 16
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define MAX_WIDTH 16
|
||||
#define PLMITEMS 2
|
||||
#define PLMITEMLENGHT 40
|
||||
|
||||
#define HIDE_IP
|
||||
#define HIDE_TITLE2
|
||||
#define HIDE_VOL
|
||||
#define HIDE_VOLBAR
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_RSSI
|
||||
#define HIDE_VU
|
||||
#define HIDE_WEATHER
|
||||
#define META_MOVE
|
||||
|
||||
//#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
#define SDELTA 2
|
||||
#define STIME 400
|
||||
const ScrollConfig metaConf PROGMEM = {{ 0, 0, 1, WA_LEFT }, 140, true, MAX_WIDTH-6, 2000, SDELTA, STIME };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ 0, 1, 1, WA_LEFT }, 140, true, MAX_WIDTH-4, 2000, SDELTA, STIME };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ 1, 1, 1, WA_LEFT }, 140, true, MAX_WIDTH-1, 2000, SDELTA, STIME };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 0, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 0, 1, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 1, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 0, 1, WA_RIGHT };
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 1, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 250, 10, 4 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
//const char bootstrFmt[] PROGMEM = "Trying to %s";
|
||||
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig metaMove PROGMEM = { 0, 0, MAX_WIDTH };
|
||||
#endif
|
||||
52
yoRadio/src/displays/conf/displayLCD2004conf.h
Normal file
52
yoRadio/src/displays/conf/displayLCD2004conf.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*************************************************************************************
|
||||
LCD2004 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayLCD2004conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayLCD1602conf_h
|
||||
#define displayLCD1602conf_h
|
||||
|
||||
#define DSP_WIDTH 20
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define MAX_WIDTH 20
|
||||
#define PLMITEMS 4
|
||||
#define PLMITEMLENGHT 40
|
||||
|
||||
#define HIDE_IP
|
||||
#define HIDE_VOLBAR
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_RSSI
|
||||
#define HIDE_VU
|
||||
#define META_MOVE
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
#define SDELTA 2
|
||||
#define STIME 300
|
||||
const ScrollConfig metaConf PROGMEM = {{ 0, 0, 1, WA_LEFT }, 140, true, MAX_WIDTH-6, 2000, SDELTA, STIME };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ 0, 1, 1, WA_LEFT }, 140, true, MAX_WIDTH-4, 2000, SDELTA, STIME };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ 0, 2, 1, WA_LEFT }, 140, true, MAX_WIDTH, 2000, SDELTA, STIME };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ 1, 1, 1, WA_LEFT }, 140, true, MAX_WIDTH-1, 2000, SDELTA, STIME };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ 0, 3, 1, WA_LEFT }, 140, false, MAX_WIDTH-4, 2000, SDELTA, STIME };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig voltxtConf PROGMEM = { 0, 3, 1, WA_RIGHT };
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 1, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 0, 1, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 2, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 0, 1, WA_RIGHT };
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 2, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 250, 10, 4 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
//#define WEATHER_FMT_SHORT
|
||||
//const char weatherFmt[] PROGMEM = "%.1fC %dmm %s%%";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig metaMove PROGMEM = { 0, 0, MAX_WIDTH };
|
||||
#endif
|
||||
68
yoRadio/src/displays/conf/displayN5110conf.h
Normal file
68
yoRadio/src/displays/conf/displayN5110conf.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*************************************************************************************
|
||||
Nokia 5110 84x48 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayN5110conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayN5110conf_h
|
||||
#define displayN5110conf_h
|
||||
|
||||
#define DSP_WIDTH 84
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define MAX_WIDTH DSP_WIDTH
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
#define SCROLLDELAY 180
|
||||
|
||||
#define HIDE_TITLE2
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_IP
|
||||
//#define HIDE_VOLBAR
|
||||
#define HIDE_RSSI
|
||||
#define HIDE_VU
|
||||
|
||||
#define bootLogoTop 0
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 5, SCROLLDELAY };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 8, 1, WA_LEFT }, 140, true, MAX_WIDTH-24, 5000, 5, SCROLLDELAY };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ 2, 22, 1, WA_LEFT }, 140, true, MAX_WIDTH-4, 1000, 5, SCROLLDELAY };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 1, WA_CENTER }, 140, false, MAX_WIDTH, 0, 5, SCROLLDELAY };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 48-7, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 5, SCROLLDELAY };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 48-11, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-2, 1000, 5, SCROLLDELAY };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 20, 0, WA_LEFT }, DSP_WIDTH, 11, false };
|
||||
//const FillConfig metaBGConf PROGMEM = {{ MAX_WIDTH-22, 9, 0, WA_LEFT }, 1, 5, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ 0, 45, 0, WA_LEFT }, MAX_WIDTH, 3, true };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 48-7, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 8, 1, WA_RIGHT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 0, 48-11, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 34, 19, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 8, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 16, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 24, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 32, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 4, 35, 19, WA_RIGHT }; /* 19 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 50, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 48-7-10, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 10, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width (0 - auto, -1 - lock } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 0, 0, -1 };
|
||||
|
||||
#endif
|
||||
71
yoRadio/src/displays/conf/displaySH1106conf.h
Normal file
71
yoRadio/src/displays/conf/displaySH1106conf.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************************
|
||||
SH1106 128x64 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displaySH1106conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displaySH1106conf_h
|
||||
#define displaySH1106conf_h
|
||||
|
||||
#define DSP_WIDTH 128
|
||||
#define TFT_FRAMEWDT 1
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_VOL
|
||||
#define HIDE_VU
|
||||
|
||||
#define bootLogoTop 8
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 3, 25 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 19, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*4, 5000, 2, 25 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 28, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 2, 25 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 30, 1, WA_LEFT }, 140, true, MAX_WIDTH, 500, 2, 25 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, 0, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 2, 25 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 64-7, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 2, 25 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 64-9, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*4, 0, 2, 25 }; // ПОГОДА!!
|
||||
|
||||
/* BACKGROUNGC9106DS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 17, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ 0, 64-1, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 26, 0, WA_LEFT }, DSP_WIDTH, 12, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 63, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 64-8, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 0, 19, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 64-9, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { 0, 64-9, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 28, 2, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 18, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 26, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 37, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 45, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 6, 38, 2, WA_CENTER };
|
||||
const WidgetConfig vuConf PROGMEM = { 1, 28, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 64-8*2-5, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 48, 2, 1, 8, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
//const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 0, 0, -1 };
|
||||
|
||||
#endif
|
||||
71
yoRadio/src/displays/conf/displaySSD1305conf.h
Normal file
71
yoRadio/src/displays/conf/displaySSD1305conf.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************************
|
||||
SSD1305 128x64 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displaySSD1305conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displaySSD1305conf_h
|
||||
#define displaySSD1305conf_h
|
||||
|
||||
#define DSP_WIDTH 128
|
||||
#define TFT_FRAMEWDT 1
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_VOL
|
||||
#define HIDE_VU
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT+1, TFT_FRAMEWDT+1, 1, WA_LEFT }, 140, true, MAX_WIDTH-2, 5000, 2, 25 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ 0, 13, 1, WA_LEFT }, 140, true, DSP_WIDTH-6*4, 5000, 2, 25 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ 0, 22, 1, WA_LEFT }, 140, true, DSP_WIDTH, 5000, 2, 25 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 30, 1, WA_LEFT }, 140, true, MAX_WIDTH, 500, 2, 25 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT+1, TFT_FRAMEWDT+1, 1, WA_CENTER }, 140, false, MAX_WIDTH-2, 0, 2, 25 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 64-7, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 2, 25 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ 0, 64-11, 1, WA_LEFT }, 140, true, DSP_WIDTH-6*4, 0, 2, 25 }; // ПОГОДА!!
|
||||
|
||||
/* BACKGROUNGC9106DS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 11, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ 0, 64-1-1-1, 0, WA_LEFT }, DSP_WIDTH, 3, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 26, 0, WA_LEFT }, DSP_WIDTH, 12, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 63, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 64-8, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 0, 13, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { 0, 64-11, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { 0, 64-11, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 26, 2, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 18, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 26, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 37, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 45, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 6, 34, 2, WA_CENTER };
|
||||
const WidgetConfig vuConf PROGMEM = { 1, 28, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 64-8*2-5, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 10, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 48, 2, 1, 8, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
//const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 0, 0, -1 };
|
||||
|
||||
#endif
|
||||
71
yoRadio/src/displays/conf/displaySSD1306conf.h
Normal file
71
yoRadio/src/displays/conf/displaySSD1306conf.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************************
|
||||
SSD1306 128x64 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displaySSD1306conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displaySSD1306conf_h
|
||||
#define displaySSD1306conf_h
|
||||
|
||||
#define DSP_WIDTH 128
|
||||
#define TFT_FRAMEWDT 1
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 5
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 18
|
||||
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_VOL
|
||||
#define HIDE_VU
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, 0, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 3, 15 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ 0, 17, 1, WA_LEFT }, 140, true, DSP_WIDTH-6*4, 5000, 2, 35 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ 0, 26, 1, WA_LEFT }, 140, true, DSP_WIDTH, 5000, 2, 35 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 26, 2, WA_LEFT }, 140, true, MAX_WIDTH, 500, 2, 25 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, 0, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 2, 35 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 64-7, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 2, 15 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ 0, 64-11, 1, WA_LEFT }, 140, true, DSP_WIDTH-6*4, 0, 2, 25 }; // ПОГОДА!!
|
||||
|
||||
/* BACKGROUNGC9106DS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 16, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ 0, 64-1-1-1, 0, WA_LEFT }, DSP_WIDTH, 3, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 23, 0, WA_LEFT }, DSP_WIDTH, 19, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 63, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 64-8, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 0, 17, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { 0, 64-11, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { 0, 64-11, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 28, 2, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 18, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 26, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 37, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 45, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 6, 36, 2, WA_CENTER };
|
||||
const WidgetConfig vuConf PROGMEM = { 1, 28, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 64-8*2-5, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 48, 2, 1, 8, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
//const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 0, 0, -1 };
|
||||
|
||||
#endif
|
||||
72
yoRadio/src/displays/conf/displaySSD1306x32conf.h
Normal file
72
yoRadio/src/displays/conf/displaySSD1306x32conf.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*************************************************************************************
|
||||
SSD1306 128x32 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displaySSD1306conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displaySSD1306conf_h
|
||||
#define displaySSD1306conf_h
|
||||
|
||||
#define DSP_WIDTH 128
|
||||
#define TFT_FRAMEWDT 1
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 5
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
|
||||
#define HIDE_IP
|
||||
#define HIDE_TITLE2
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_VU
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*5-2, 5000, 2, 25 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ 0, 11, 1, WA_LEFT }, 140, true, DSP_WIDTH-6*4, 5000, 2, 25 };
|
||||
//const ScrollConfig title2Conf PROGMEM = {{ 0, 26, 1, WA_LEFT }, 140, true, DSP_WIDTH, 5000, 2, 35 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 14, 1, WA_LEFT }, 140, true, MAX_WIDTH, 500, 2, 25 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, 1, 1, WA_CENTER }, 140, false, MAX_WIDTH, 0, 2, 25 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 32-7, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 2, 25 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ 0, 20, 1, WA_LEFT }, 140, true, DSP_WIDTH-6*4, 0, 2, 25 }; // ПОГОДА!!
|
||||
|
||||
/* BACKGROUNGC9106DS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH/*-6*5-3*/, 9, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ 0, 32-1-1-1, 0, WA_LEFT }, DSP_WIDTH, 3, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 13, 0, WA_LEFT }, DSP_WIDTH, 9, false };
|
||||
//const FillConfig heapbarConf PROGMEM = {{ 0, 63, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 32-8, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 0, 11, 1, WA_RIGHT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 0, 20, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { 0, 64-11, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { 0, 64-11, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 12, 2, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 9, 1, WA_LEFT };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 9, 1, WA_RIGHT };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 17, 1, WA_LEFT };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 17, 1, WA_RIGHT };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 1, 1, WA_RIGHT };
|
||||
//const WidgetConfig vuConf PROGMEM = { 1, 28, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 32-8*2-5, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 10, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 48, 2, 1, 8, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 0, 0, -1 };
|
||||
|
||||
#endif
|
||||
71
yoRadio/src/displays/conf/displaySSD1327conf.h
Normal file
71
yoRadio/src/displays/conf/displaySSD1327conf.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************************
|
||||
SSD1327 128x128 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displaySSD1327conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displaySSD1327conf_h
|
||||
#define displaySSD1327conf_h
|
||||
|
||||
#define DSP_WIDTH 128
|
||||
#define TFT_FRAMEWDT 4
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 21
|
||||
|
||||
#define HIDE_HEAPBAR
|
||||
#define HIDE_VU
|
||||
|
||||
#define bootLogoTop 34
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 26, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 2, 30 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 36, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-4, 5000, 2, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 56, 2, WA_LEFT }, 140, true, MAX_WIDTH, 1000, 4, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 128-TFT_FRAMEWDT-8, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 2, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 42, 1, WA_LEFT }, 140, true, MAX_WIDTH, 0, 3, 30 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 118, 0, WA_LEFT }, MAX_WIDTH-6*3-4, 5, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 52, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 127, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 110, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 36, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { TFT_FRAMEWDT, 128-10, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 86, 35, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 40, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 54, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 74, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 88, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 94, 35, WA_RIGHT }; /* 35 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 99, 1, WA_CENTER };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 90, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 56, 7, 2, 1, 8, 2 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width (0 - auto, -1 - lock } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 94, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { TFT_FRAMEWDT, 48, 122 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { TFT_FRAMEWDT, 48, 122 };
|
||||
|
||||
#endif
|
||||
68
yoRadio/src/displays/conf/displayST7735_144conf.h
Normal file
68
yoRadio/src/displays/conf/displayST7735_144conf.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*************************************************************************************
|
||||
ST7735 128x128 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayST7735conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayST7789conf_h
|
||||
#define displayST7789conf_h
|
||||
|
||||
#define DSP_WIDTH 128
|
||||
#define TFT_FRAMEWDT 4
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 21
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 26, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 2, 30 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 36, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-4, 5000, 2, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 56, 2, WA_LEFT }, 140, true, MAX_WIDTH, 1000, 4, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 128-TFT_FRAMEWDT-8, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 2, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 42, 1, WA_LEFT }, 140, true, MAX_WIDTH, 0, 3, 30 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 118, 0, WA_LEFT }, MAX_WIDTH-6*3-4, 5, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 52, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 127, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 110, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 36, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { TFT_FRAMEWDT, 128-10, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 86, 35, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 40, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 54, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 74, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 88, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 94, 35, WA_RIGHT }; /* 35 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 99, 1, WA_CENTER };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 90, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 56, 7, 2, 1, 8, 2 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
|
||||
/* MOVES */ /* { left, top, width (0 - auto, -1 - lock } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 94, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { TFT_FRAMEWDT, 48, 122 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { TFT_FRAMEWDT, 48, 122 };
|
||||
|
||||
#endif
|
||||
67
yoRadio/src/displays/conf/displayST7735_blackconf.h
Normal file
67
yoRadio/src/displays/conf/displayST7735_blackconf.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*************************************************************************************
|
||||
ST7735 160x128 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayST7735conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
#ifndef displayST7735conf_h
|
||||
#define displayST7735conf_h
|
||||
|
||||
#define DSP_WIDTH 160
|
||||
#define TFT_FRAMEWDT 4
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 21
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 26, 1, WA_LEFT }, 140, true, MAX_WIDTH-24, 5000, 3, 30 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 36, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 3, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 56, 2, WA_LEFT }, 140, true, MAX_WIDTH, 1000, 4, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 128-TFT_FRAMEWDT-8, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 42, 1, WA_LEFT }, 140, true, MAX_WIDTH, 0, 3, 30 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 118, 0, WA_LEFT }, MAX_WIDTH, 5, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 52, 0, WA_LEFT }, DSP_WIDTH, 22, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 127, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 110, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 26, 1, WA_RIGHT };
|
||||
//const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 99, 1, WA_LEFT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 86, 35, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 40, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 54, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 74, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 88, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 94, 35, WA_RIGHT }; /* 35 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 54, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 90, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 50, 2, 1, 10, 3 };
|
||||
|
||||
const BitrateConfig fullbitrateConf PROGMEM = {{DSP_WIDTH-TFT_FRAMEWDT-19, 23, 1, WA_LEFT}, 22 };
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
/* MOVES */ /* { left, top, width (0 - auto, -1 - lock } */
|
||||
const MoveConfig clockMove PROGMEM = { 16, 94, 0};
|
||||
const MoveConfig weatherMove PROGMEM = {TFT_FRAMEWDT, 48, MAX_WIDTH};
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 34, 48, 122 };
|
||||
|
||||
#endif
|
||||
71
yoRadio/src/displays/conf/displayST7735_miniconf.h
Normal file
71
yoRadio/src/displays/conf/displayST7735_miniconf.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************************
|
||||
ST7735 160x80 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayST7735conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayST7789conf_h
|
||||
#define displayST7789conf_h
|
||||
|
||||
#define DSP_WIDTH 160
|
||||
#define TFT_FRAMEWDT 1
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 19
|
||||
|
||||
#define HIDE_IP
|
||||
#define HIDE_TITLE2
|
||||
#define HIDE_VOL
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 19, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-4, 5000, 3, 30 };
|
||||
//const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 36, 1, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 2, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 33, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 2, WA_CENTER }, 140, false, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 80-TFT_FRAMEWDT-8, 1, WA_LEFT }, 140, false, MAX_WIDTH, 0, 3, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 80-13, 1, WA_LEFT }, 140, true, MAX_WIDTH-6*3-4, 0, 3, 30 }; // ПОГОДА!!
|
||||
|
||||
/* BACKGROUNGC9106DS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 16, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 80-1-1-2, 0, WA_LEFT }, MAX_WIDTH, 2, false };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 30, 0, WA_LEFT }, DSP_WIDTH, 20, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 79, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 65, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 19, 1, WA_RIGHT };
|
||||
//const WidgetConfig voltxtConf PROGMEM = { 32, 108, 1, WA_RIGHT };
|
||||
//const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 108, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 80-13, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 29+32, 35, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { 0, 20, 1, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { 0, 32, 1, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { 0, 46, 1, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { 0, 58, 1, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 29+34, 35, WA_RIGHT }; /* 35 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { 1, 28, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 50, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 12, 48, 2, 1, 8, 3 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "%d";
|
||||
//const char iptxtFmt[] PROGMEM = "%s";
|
||||
//const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d";
|
||||
*/
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 14, 29+34, 0};
|
||||
const MoveConfig weatherMove PROGMEM = { TFT_FRAMEWDT, 80-13, MAX_WIDTH-6*3-4-30 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 30, 80-13, MAX_WIDTH-6*3-4-30 };
|
||||
|
||||
#endif
|
||||
66
yoRadio/src/displays/conf/displayST7789_240conf.h
Normal file
66
yoRadio/src/displays/conf/displayST7789_240conf.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*************************************************************************************
|
||||
ST7789 240x240 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayST7789conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayST7789conf_h
|
||||
#define displayST7789conf_h
|
||||
|
||||
#define DSP_WIDTH 240
|
||||
#define TFT_FRAMEWDT 8
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 11
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 3, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 5, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 50, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 70, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 112, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 2, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 3, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 20 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 240-TFT_FRAMEWDT-16, 2, WA_LEFT }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 198, 1, WA_LEFT }, 140, true, MAX_WIDTH, 0, 3, 30 };
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 38, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 240-TFT_FRAMEWDT-6, 0, WA_LEFT }, MAX_WIDTH, 6, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 107, 0, WA_LEFT }, DSP_WIDTH, 24, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 239, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 182, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { TFT_FRAMEWDT, 188, 1, WA_LEFT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 80, 214, 1, WA_RIGHT };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 214, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 214, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 120+30, 52, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { TFT_FRAMEWDT, 66, 2, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { TFT_FRAMEWDT, 90, 2, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { TFT_FRAMEWDT, 130, 2, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { TFT_FRAMEWDT, 154, 2, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 0, 168, 52, WA_RIGHT }; /* 52 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 94, 1, WA_CENTER };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 162, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 100, 20, 10, 2, 10, 5 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "WiFi %d";
|
||||
const char iptxtFmt[] PROGMEM = "IP %s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d kBs";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 176, 0 };
|
||||
const MoveConfig weatherMove PROGMEM = { TFT_FRAMEWDT, 202, MAX_WIDTH };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { TFT_FRAMEWDT, 202, MAX_WIDTH };
|
||||
|
||||
#endif
|
||||
67
yoRadio/src/displays/conf/displayST7789conf.h
Normal file
67
yoRadio/src/displays/conf/displayST7789conf.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*************************************************************************************
|
||||
ST7789 320x240 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayST7789conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayST7789conf_h
|
||||
#define displayST7789conf_h
|
||||
|
||||
#define DSP_WIDTH 320
|
||||
#define TFT_FRAMEWDT 8
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 11
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
|
||||
#define bootLogoTop 68
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 3, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 5, 30 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 50, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 70, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 4, 30 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 112, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 2, 30 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 3, WA_CENTER }, 140, false, MAX_WIDTH, 0, 4, 20 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 240-TFT_FRAMEWDT-16, 2, WA_LEFT }, 140, false, MAX_WIDTH, 0, 4, 30 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ 8, 87, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 4, 30 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 38, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, 240-TFT_FRAMEWDT-6, 0, WA_LEFT }, MAX_WIDTH, 6, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 107, 0, WA_LEFT }, DSP_WIDTH, 24, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, 239, 0, WA_LEFT }, DSP_WIDTH, 1, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 182, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 70, 191, 1, WA_LEFT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 0, 214, 1, WA_CENTER };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, 214, 1, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, 214, 1, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 120+30, 52, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { TFT_FRAMEWDT, 66, 2, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { TFT_FRAMEWDT, 90, 2, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { TFT_FRAMEWDT, 130, 2, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { TFT_FRAMEWDT, 154, 2, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 12, 176, 52, WA_RIGHT }; /* 52 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 100, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 162, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 24, 100, 4, 2, 10, 5 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "WiFi %d";
|
||||
const char iptxtFmt[] PROGMEM = "IP %s";
|
||||
const char voltxtFmt[] PROGMEM = "vol %d";
|
||||
const char bitrateFmt[] PROGMEM = "%d kBs";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 176, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 8, 97, MAX_WIDTH };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 70, 97, 250 };
|
||||
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
#ifndef displayDummy_h
|
||||
#define displayDummy_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#define TFT_FRAMEWDT 4
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 3
|
||||
#define SCROLLTIME 60
|
||||
#endif
|
||||
|
||||
#define DSP_FLIPPED 0
|
||||
|
||||
class DspCore {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
/*
|
||||
* TFT COLORS
|
||||
*/
|
||||
#define BLACK 0x0000
|
||||
#define BLUE 0x001F
|
||||
#define RED 0xF800
|
||||
#define GREEN 0x07E0
|
||||
#define MAGENTA 0xF81F
|
||||
#define YELLOW 0xFFE0
|
||||
#define WHITE 0xFFFF
|
||||
#define GRAY 0x7BEF
|
||||
#define DARK_GRAY 0x2945
|
||||
#define LIGHT_GRAY 0xC618
|
||||
#define LIME 0x87E0
|
||||
#define AQUA 0x5D1C
|
||||
#define CYAN 0x07FF
|
||||
#define DARK_CYAN 0x03EF
|
||||
#define ORANGE 0xFCA0
|
||||
#define PINK 0xF97F
|
||||
#define BROWN 0x8200
|
||||
#define VIOLET 0x9199
|
||||
#define SILVER 0xA510
|
||||
#define GOLD 0xA508
|
||||
#define NAVY 0x000F
|
||||
#define MAROON 0x7800
|
||||
#define PURPLE 0x780F
|
||||
#define OLIVE 0x7BE0
|
||||
|
||||
#define TFT_BG BLACK
|
||||
#define TFT_FG WHITE
|
||||
#define TFT_LOGO 0xE68B // 224, 209, 92
|
||||
|
||||
#endif
|
||||
@@ -1,135 +1,33 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_GC9106
|
||||
|
||||
#include "displayGC9106.h"
|
||||
#include <SPI.h>
|
||||
#include "fonts/bootlogo40.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef DEF_SPI_FREQ
|
||||
#define DEF_SPI_FREQ 24000000 /* set it to 0 for system default */
|
||||
#define DEF_SPI_FREQ 24000000 /* set it to 0 for system default */
|
||||
#endif
|
||||
|
||||
#define CLOCK_DELTA 16
|
||||
|
||||
#define TAKE_MUTEX() if(player.mutex_pl) xSemaphoreTake(player.mutex_pl, portMAX_DELAY)
|
||||
#define GIVE_MUTEX() if(player.mutex_pl) xSemaphoreGive(player.mutex_pl)
|
||||
|
||||
DspCore::DspCore(): Adafruit_GC9106Ex(TFT_CS, TFT_DC, TFT_RST) {
|
||||
DspCore::DspCore(): Adafruit_GC9106Ex(TFT_CS, TFT_DC, TFT_RST) { }
|
||||
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.title1, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 2 * TFT_LINEHGHT);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 3 * TFT_LINEHGHT);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(config.theme.title2, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, 107);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, 117);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
begin(DEF_SPI_FREQ);
|
||||
cp437(true);
|
||||
invert();
|
||||
// fillScreen(TFT_BG);
|
||||
flip();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
setClockBounds();
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
fillScreen(0x0000);
|
||||
drawRGBBitmap((swidth - 62) / 2, 5, bootlogo40, 62, 40);
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
drawRGBBitmap((width() - 62) / 2, 5, bootlogo40, 62, 40);
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
@@ -138,8 +36,7 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 3, PLMITEMS);
|
||||
setTextSize(2);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
//fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) - 1, swidth, PLMITEMHEIGHT + 2, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (abs(i - 3) == 3) setTextColor(config.theme.playlist[2], config.theme.background);
|
||||
if (abs(i - 3) == 2) setTextColor(config.theme.playlist[1], config.theme.background);
|
||||
@@ -148,181 +45,77 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, swidth, PLMITEMHEIGHT - 4, config.theme.background);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, width(), PLMITEMHEIGHT - 4, config.theme.background);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
fillScreen(config.theme.background);
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(black?0:config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI28pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop-2, swidth, textheight+3, bg);
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(txt);
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, y, w, h, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::setClockBounds(){
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
getTextBounds("88:88", 0, 0, &x, &y, &cwidth, &cheight);
|
||||
uint16_t header = TFT_FRAMEWDT + 4 * TFT_LINEHGHT;
|
||||
uint16_t footer = TFT_FRAMEWDT * 2 + TFT_LINEHGHT + 5;
|
||||
clockY = header + (sheight - header - footer) / 2 - cheight / 2 - 6;
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
}
|
||||
|
||||
byte DspCore::getPw(uint16_t ncwidth){
|
||||
byte pw = 6;
|
||||
if(ncwidth<35) pw = 7;
|
||||
if(ncwidth<20) pw = 8;
|
||||
return pw;
|
||||
}
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
|
||||
char timeBuf[50] = { 0 };
|
||||
char tmpBuf[4] = { 0 };
|
||||
uint16_t ncwidth, ncheight;
|
||||
uint16_t clockdelta=config.store.vumeter?CLOCK_DELTA:0;
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H %M", &timeinfo);
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = (width()/2 - _timewidth/2)+clockRightSpace;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot);
|
||||
setCursor((swidth - wot) / 2 - 4 + clockdelta, clockY+28+6);
|
||||
setTextColor(config.theme.background);
|
||||
print(oldTimeBuf);
|
||||
dot = (swidth - wot) / 2 - 4 + clockdelta;
|
||||
/* dots */
|
||||
strlcpy(tmpBuf, oldTimeBuf, 3);
|
||||
getTextBounds(tmpBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
dot = dot + ncwidth + getPw(ncwidth);
|
||||
setCursor(dot, clockY+28+6);
|
||||
print(":");
|
||||
/* dots */
|
||||
|
||||
strlcpy(oldTimeBuf, timeBuf, 20);
|
||||
setTextSize(1);
|
||||
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
setTextColor(config.theme.clock);
|
||||
setCursor((swidth - ncwidth) / 2 - 4 + clockdelta, clockY+28+6);
|
||||
dot = (swidth - ncwidth) / 2 - 4 + clockdelta;
|
||||
setTextSize(1);
|
||||
print(timeBuf);
|
||||
/* dots */
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H", &timeinfo);
|
||||
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
dot = dot + ncwidth + getPw(ncwidth);
|
||||
/* dots */
|
||||
}
|
||||
setCursor(dot, clockY+28+6);
|
||||
setTextColor(dots?config.theme.background:config.theme.clock);
|
||||
print(":");
|
||||
setFont();
|
||||
yield();
|
||||
}
|
||||
|
||||
#define VTOP TITLE_TOP1+6
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT - 2;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT * 2;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth);
|
||||
fillRect(TFT_FRAMEWDT, vTop, vWidth, 2, config.theme.background);
|
||||
fillRect(TFT_FRAMEWDT, vTop, ww, 2, config.theme.volbarout);
|
||||
if (withNumber) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, VTOP, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, VTOP + hv);
|
||||
print(volstr);
|
||||
setFont();
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, VTOP, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, VTOP + hv);
|
||||
print(numstr);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(2);
|
||||
centerText(str, TFT_FRAMEWDT, config.theme.meta, config.theme.background);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
setTextSize(1);
|
||||
rightText(str, vTop, config.theme.rssi, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.ip, config.theme.background);
|
||||
setCursor(4, vTop);
|
||||
print(str);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*3*2+24, clockTimeHeight+10+CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::startWrite(void) {
|
||||
@@ -335,45 +128,17 @@ void DspCore::endWrite(void) {
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
/*
|
||||
void DspCore::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8_t numDataBytes) {
|
||||
TAKE_MUTEX();
|
||||
Adafruit_GC9106Ex::sendCommand(commandByte, dataBytes, numDataBytes);
|
||||
GIVE_MUTEX();
|
||||
void DspCore::loop(bool force) { }
|
||||
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) {
|
||||
TAKE_MUTEX();
|
||||
Adafruit_GC9106Ex::sendCommand(commandByte, dataBytes, numDataBytes);
|
||||
GIVE_MUTEX();
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::sendCommand16(uint16_t commandWord, const uint8_t *dataBytes, uint8_t numDataBytes) {
|
||||
TAKE_MUTEX();
|
||||
Adafruit_GC9106Ex::sendCommand16(commandWord, dataBytes, numDataBytes);
|
||||
GIVE_MUTEX();
|
||||
}*/
|
||||
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
}
|
||||
void DspCore::flip(){
|
||||
setRotation(config.store.flipscreen?1:3);
|
||||
}
|
||||
@@ -385,4 +150,33 @@ void DspCore::invert(){
|
||||
void DspCore::sleep(void) { sendCommand(GC9106_SLPIN); delay(150); sendCommand(GC9106_DISPOFF); delay(150); }
|
||||
void DspCore::wake(void) { sendCommand(GC9106_DISPON); delay(150); sendCommand(GC9106_SLPOUT); delay(150); }
|
||||
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_GC9106Ex::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_GC9106Ex::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,118 +1,34 @@
|
||||
#ifndef displayGC9106_h
|
||||
#define displayGC9106_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
/* https://github.com/prenticedavid/Adafruit_GC9102_kbv */
|
||||
#include "../Adafruit_GC9106Ex/Adafruit_GC9106Ex.h"
|
||||
#include "fonts/DS_DIGI28pt7b.h"
|
||||
#include "../Adafruit_GC9106Ex/Adafruit_GC9106Ex.h" // https://github.com/prenticedavid/Adafruit_GC9102_kbv
|
||||
#include "fonts/DS_DIGI28pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define VU_READY 1
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#define TFT_FRAMEWDT 0
|
||||
typedef GFXcanvas16 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 19
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 3
|
||||
#define SCROLLTIME 30
|
||||
#if __has_include("conf/displayGC9106conf_custom.h")
|
||||
#include "conf/displayGC9106conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayGC9106conf.h"
|
||||
#endif
|
||||
|
||||
#define TFT_FULLTIME 1
|
||||
|
||||
#define TITLE_SIZE2 0
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + 2 * TFT_LINEHGHT-3
|
||||
|
||||
#define BOOTSTR_TOP1 50
|
||||
#define BOOTSTR_TOP2 65
|
||||
#define BOOT_PRG_COLOR 0xE68B
|
||||
#define BOOT_TXT_COLOR 0xFFFF
|
||||
#define PINK 0xF97F
|
||||
|
||||
class DspCore: public Adafruit_GC9106Ex {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
virtual void startWrite(void);
|
||||
virtual void endWrite(void);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
/*virtual void sendCommand(uint8_t commandByte, uint8_t *dataBytes,
|
||||
uint8_t numDataBytes);
|
||||
virtual void sendCommand(uint8_t commandByte, const uint8_t *dataBytes = NULL,
|
||||
uint8_t numDataBytes = 0);
|
||||
virtual void sendCommand16(uint16_t commandWord, const uint8_t *dataBytes = NULL,
|
||||
uint8_t numDataBytes = 0);*/
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
char oldTimeBuf[20];
|
||||
uint16_t wot, hot, dot;
|
||||
int16_t x, y;
|
||||
uint16_t cwidth, cheight;
|
||||
void setClockBounds();
|
||||
byte getPw(uint16_t ncwidth);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
/*
|
||||
* TFT COLORS
|
||||
*/
|
||||
/*#define BLACK 0x0000
|
||||
#define BLUE 0x001F
|
||||
#define RED 0xF800
|
||||
#define GREEN 0x07E0
|
||||
#define MAGENTA 0xF81F
|
||||
#define YELLOW 0xFFE0
|
||||
#define WHITE 0xFFFF
|
||||
#define GRAY 0x7BEF
|
||||
#define DARK_GRAY 0x2945
|
||||
#define LIGHT_GRAY 0xC618
|
||||
#define LIME 0x87E0
|
||||
#define AQUA 0x5D1C
|
||||
#define CYAN 0x07FF
|
||||
#define DARK_CYAN 0x03EF
|
||||
#define ORANGE 0xFCA0
|
||||
#define PINK 0xF97F
|
||||
#define BROWN 0x8200
|
||||
#define VIOLET 0x9199
|
||||
#define SILVER 0xA510
|
||||
#define GOLD 0xA508
|
||||
#define NAVY 0x000F
|
||||
#define MAROON 0x7800
|
||||
#define PURPLE 0x780F
|
||||
#define OLIVE 0x7BE0
|
||||
|
||||
#define TFT_BG BLACK
|
||||
#define TFT_FG WHITE
|
||||
#define TFT_LOGO 0xE68B // 224, 209, 92*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ILI9225
|
||||
|
||||
#include "displayILI9225.h"
|
||||
#include <SPI.h>
|
||||
#include "fonts/bootlogo.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
const char *dow[7] = {"вс","пн","вт","ср","чт","пт","сб"};
|
||||
const char *mnths[12] = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"};
|
||||
extern unsigned char yofont5x7[];
|
||||
extern unsigned char yofont10x14[];
|
||||
|
||||
@@ -21,102 +19,7 @@ DspCore::DspCore(): TFT_22_ILI9225(TFT_RST, TFT_DC, TFT_CS, 0) {
|
||||
|
||||
}
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
started = true;
|
||||
clearDsp();
|
||||
setTextSize(TITLE_SIZE1);
|
||||
setTextColor(config.theme.title1, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, TITLE_TOP1);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TITLE_TOP2);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(config.theme.title2, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, sheight-TFT_FRAMEWDT-TFT_LINEHGHT*4);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight-TFT_FRAMEWDT-TFT_LINEHGHT*2);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
TAKE_MUTEX();
|
||||
drawLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, TITLE_TOP1-8, config.theme.div);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
if(s==2){
|
||||
@@ -127,59 +30,44 @@ void DspCore::setTextSize(uint8_t s){
|
||||
}
|
||||
|
||||
void DspCore::setTextColor(uint16_t fg, uint16_t bg){
|
||||
bgcolor=bg;
|
||||
setBackgroundColor(bgcolor);
|
||||
fgcolor=fg;
|
||||
_bgcolor=bg;
|
||||
setBackgroundColor(_bgcolor);
|
||||
_fgcolor=fg;
|
||||
}
|
||||
|
||||
void DspCore::setCursor(int16_t x, int16_t y){
|
||||
cursorx=x;
|
||||
cursory=y;
|
||||
_cursorx=x;
|
||||
_cursory=y;
|
||||
}
|
||||
|
||||
uint16_t DspCore::print(const char* s){
|
||||
TAKE_MUTEX();
|
||||
if(gFont){
|
||||
drawGFXText(cursorx, cursory, s, fgcolor);
|
||||
if(_gFont){
|
||||
drawGFXText(_cursorx, _cursory, s, _fgcolor);
|
||||
GIVE_MUTEX();
|
||||
return 0;
|
||||
}else{
|
||||
cursorx=drawText(cursorx, cursory, s, fgcolor);
|
||||
_cursorx=drawText(_cursorx, _cursory, s, _fgcolor);
|
||||
GIVE_MUTEX();
|
||||
return cursorx;
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1,
|
||||
int16_t *y1, uint16_t *w, uint16_t *h){
|
||||
if(!gFont){
|
||||
_currentFont cfont = getFont();
|
||||
*w = getTextWidth(string);
|
||||
*h = cfont.height;
|
||||
}else{
|
||||
int16_t iw, ih;
|
||||
getGFXTextExtent(string, x, y, &iw, &ih);
|
||||
*w = (uint16_t)iw;
|
||||
*h = (uint16_t)ih;
|
||||
return _cursorx;
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::setFont(uint8_t* font, bool monoSp) {
|
||||
gFont = false;
|
||||
_gFont = false;
|
||||
TFT_22_ILI9225::setFont(font, monoSp);
|
||||
}
|
||||
|
||||
void DspCore::setFont(const GFXfont *f) {
|
||||
if (f) {
|
||||
gFont = true;
|
||||
_gFont = true;
|
||||
setGFXFont(f);
|
||||
} else {
|
||||
setFont(yofont5x7, false);
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
||||
uint16_t color) {
|
||||
void DspCore::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(y<0){
|
||||
h=h+y;
|
||||
y=0;
|
||||
@@ -189,24 +77,37 @@ void DspCore::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
//hspi.begin();
|
||||
started = false;
|
||||
begin();
|
||||
invert();
|
||||
// clear(0x0000);
|
||||
flip();
|
||||
setTextSize(1);
|
||||
screenwidth = maxX();
|
||||
screenheight = maxY();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
void DspCore::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
|
||||
TAKE_MUTEX();
|
||||
drawRectangle(x, y, x+w, y+h, color);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
// setBackgroundColor(0x0000);
|
||||
drawBitmap((swidth - 99) / 2, (sheight-64)/2 - TFT_LINEHGHT*2, bootlogo2, 99, 64);
|
||||
// setBackgroundColor(config.theme.background);
|
||||
void DspCore::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
|
||||
TAKE_MUTEX();
|
||||
drawLine(x, y, x, y+h, color);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
|
||||
TAKE_MUTEX();
|
||||
drawLine(x, y, x+w, y, color);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::initDisplay() {
|
||||
TAKE_MUTEX();
|
||||
begin();
|
||||
invert();
|
||||
flip();
|
||||
setTextSize(1);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
TAKE_MUTEX();
|
||||
drawBitmap((width() - 99) / 2, top, bootlogo2, 99, 64);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
@@ -215,242 +116,124 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 4, PLMITEMS);
|
||||
setTextSize(2);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) - 1, swidth, PLMITEMHEIGHT, config.theme.meta);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 4) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setTextColor(config.theme.playlist[abs(i - 4)-1], config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT-1, swidth, PLMITEMHEIGHT-7, config.theme.background);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT-1, width(), PLMITEMHEIGHT-7, config.theme.background);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
//fillRect(0, 0, swidth, sheight, config.theme.background);
|
||||
void DspCore::clearDsp(bool black) {
|
||||
TAKE_MUTEX();
|
||||
clear(started?config.theme.background:0x0000);
|
||||
clear(black?0x0000:config.theme.background);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT==0) return;
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(0, texttop, TFT_FRAMEWDT-1, textheight, bg);
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI28pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, uint16_t y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
if(y==90) y=(sheight-64)/2 + 64 + TFT_LINEHGHT;
|
||||
if(y==110) y=(sheight-64)/2 + 64 + TFT_LINEHGHT*3;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg, bg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect((swidth-w)/2-5, y, w+10, h, bg);
|
||||
print(txt);
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, uint16_t y, uint16_t fg, uint16_t bg, bool fliprect, uint16_t delta) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT - delta, y);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT * 2 - 2;
|
||||
char buf[50];
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.heap, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, config.theme.background);
|
||||
sprintf(buf, "%d / %d", ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
print(buf);
|
||||
// audio buffer;
|
||||
fillRect(0, sheight - 2, swidth, 2, config.theme.background);
|
||||
int astored = player.inBufferFilled();
|
||||
int afree = player.inBufferFree();
|
||||
int aprcnt = 100 * astored / (astored + afree);
|
||||
uint16_t sbw = map(aprcnt, 0, 100 , 0, swidth);
|
||||
fillRect(0, sheight - 2, sbw, 2, config.theme.buffer);
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
|
||||
}
|
||||
|
||||
uint16_t cltop = 0;
|
||||
uint8_t clsp = 24;
|
||||
uint16_t clleft = 0;
|
||||
uint16_t clwidth = 0;
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
|
||||
char timeBuf[50] = { 0 };
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H:%M", &timeinfo);
|
||||
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
|
||||
int16_t x1, y1;
|
||||
gFont=true;
|
||||
setGFXFont(&DS_DIGI28pt7b);
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x1, &y1, &wot, &hot);
|
||||
if(cltop==0){
|
||||
cltop=sheight-(TFT_FRAMEWDT * 2 + TFT_LINEHGHT + 38) - hot;
|
||||
}
|
||||
clwidth = wot+clsp+34;
|
||||
clleft=swidth-TFT_FRAMEWDT-clwidth;
|
||||
setCursor(clleft, cltop);
|
||||
setTextColor(config.theme.background, config.theme.background);
|
||||
print(oldTimeBuf);
|
||||
strlcpy(oldTimeBuf, timeBuf, 20);
|
||||
getTextBounds(timeBuf, 0, 0, &x1, &y1, &wot, &hot);
|
||||
clwidth = wot+clsp+34;
|
||||
clleft=swidth-TFT_FRAMEWDT-clwidth;
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(clleft, cltop);
|
||||
print(timeBuf);
|
||||
gFont=false;
|
||||
setTextSize(2);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(clleft+wot+clsp, cltop-hot+22);
|
||||
print(utf8Rus(dow[timeinfo.tm_wday], false));
|
||||
TAKE_MUTEX();
|
||||
drawLine(clleft+wot+clsp/2, cltop-34, clleft+wot+clsp/2, cltop+1, config.theme.div); //vert
|
||||
drawLine(clleft+wot+clsp/2, cltop-hot+20, clleft+wot+clsp/2+35, cltop-hot+20, config.theme.div); //hor
|
||||
drawLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, TITLE_TOP1-8, config.theme.div);
|
||||
GIVE_MUTEX();
|
||||
sprintf(timeBuf, "%2d %s %d", timeinfo.tm_mday,mnths[timeinfo.tm_mon], timeinfo.tm_year+1900);
|
||||
uint16_t wdate, hdate;
|
||||
getTextBounds(timeBuf, 0, 0, &x1, &y1, &wdate, &hdate);
|
||||
fillRect(swidth - wdate - TFT_FRAMEWDT-20, cltop+10, wdate+20, hdate, config.theme.background);
|
||||
setTextSize(1);
|
||||
rightText(utf8Rus(timeBuf,true), cltop+10, config.theme.date, config.theme.background, false, 12);
|
||||
}
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(2);
|
||||
setTextColor(config.theme.seconds, config.theme.background);
|
||||
setCursor(clleft+wot+clsp, cltop-hot+1);
|
||||
sprintf(timeBuf, "%02d", timeinfo.tm_sec);
|
||||
print(timeBuf);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*2*2, clockTop-clockTimeHeight+1);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds); /* print seconds */
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2;
|
||||
int16_t volTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT *2;
|
||||
(void)volTop;
|
||||
uint16_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, config.theme.background);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop - 1, ww, 5, config.theme.volbarin);
|
||||
drawRectangle(TFT_FRAMEWDT, vTop - 2, TFT_FRAMEWDT+vWidth, 6+vTop - 2, config.theme.volbarout);
|
||||
|
||||
if (withNumber) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit, config.theme.background);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
|
||||
/*setTextColor(TFT_BG);
|
||||
sprintf(volstr, "%d", oldVolume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(volstr);*/
|
||||
sprintf(volstr, "%d", oldVolume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect((swidth - wv) / 2 - 12, (sheight-hv)/2, wv+24, hv, config.theme.background);
|
||||
|
||||
setTextColor(config.theme.vol, config.theme.background);
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(volstr);
|
||||
oldVolume=config.store.volume;
|
||||
}
|
||||
void DspCore::_clockDate(){
|
||||
if(_olddateleft>0)
|
||||
fillRect(_olddateleft, clockTop+10, _olddatewidth, CHARHEIGHT, config.theme.background);
|
||||
setTextColor(config.theme.date, config.theme.background);
|
||||
setCursor(_dateleft, clockTop+10);
|
||||
print(_dateBuf); /* print date */
|
||||
strlcpy(_oldDateBuf, _dateBuf, sizeof(_dateBuf));
|
||||
_olddatewidth = _datewidth;
|
||||
_olddateleft = _dateleft;
|
||||
setTextSize(2);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*2*2, clockTop-CHARHEIGHT*2+4);
|
||||
print(utf8Rus(dow[network.timeinfo.tm_wday], false)); /* print dow */
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = width()-clockRightSpace-CHARWIDTH*2*2-24-_timewidth;
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit, config.theme.background);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, (sheight-hv)/2, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(numstr);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
drawFastVLine(width()-clockRightSpace-CHARWIDTH*2*2-18, clockTop-clockTimeHeight, clockTimeHeight+3, config.theme.div); /*divider vert*/
|
||||
drawFastHLine(width()-clockRightSpace-CHARWIDTH*2*2-18, clockTop-clockTimeHeight+21, 32, config.theme.div); /*divider hor*/
|
||||
sprintf(_buffordate, "%2d %s %d", network.timeinfo.tm_mday,mnths[network.timeinfo.tm_mon], network.timeinfo.tm_year+1900);
|
||||
strlcpy(_dateBuf, utf8Rus(_buffordate, true), sizeof(_dateBuf));
|
||||
_datewidth = strlen(_dateBuf) * CHARWIDTH;
|
||||
_dateleft = width() - 8 - clockRightSpace - _datewidth;
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(META_SIZE);
|
||||
centerText(str, TFT_FRAMEWDT, config.theme.meta, config.theme.background);
|
||||
TAKE_MUTEX();
|
||||
drawLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, TITLE_TOP1-8, config.theme.div);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
char buf[20];
|
||||
sprintf(buf, "RSSI:%s", str);
|
||||
setTextSize(1);
|
||||
rightText(buf, vTop, config.theme.rssi, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
if(!started){
|
||||
started = true;
|
||||
clear(config.theme.background);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
if(strcmp(_oldDateBuf, _dateBuf)!=0 || redraw) _clockDate();
|
||||
}
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
char buf[30];
|
||||
sprintf(buf, "IP: %s", str);
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.ip, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
print(buf);
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::clearClock(){
|
||||
fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*3*2+24, clockTimeHeight+10+CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
void DspCore::startWrite(void) {
|
||||
//TAKE_MUTEX();
|
||||
TFT_22_ILI9225::startWrite();
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
void DspCore::endWrite(void) {
|
||||
TFT_22_ILI9225::endWrite();
|
||||
//GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
void DspCore::loop(bool force) {
|
||||
//delay(5);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::drawRGBBitmap(int16_t x, int16_t y, const uint16_t *bitmap, int16_t w, int16_t h) {
|
||||
@@ -458,14 +241,46 @@ void DspCore::drawRGBBitmap(int16_t x, int16_t y, const uint16_t *bitmap, int16_
|
||||
drawBitmap(x, y, bitmap, w, h);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
TAKE_MUTEX();
|
||||
setOrientation(config.store.flipscreen?3:1);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
void DspCore::invert(){
|
||||
TAKE_MUTEX();
|
||||
invertDisplay(config.store.invertdisplay);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::sleep(void) { setDisplay(false); }
|
||||
void DspCore::wake(void) { setDisplay(true); }
|
||||
void DspCore::sleep(void) { TAKE_MUTEX(); setDisplay(false); GIVE_MUTEX(); }
|
||||
void DspCore::wake(void) { TAKE_MUTEX(); setDisplay(true); GIVE_MUTEX(); }
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) { }
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { }
|
||||
|
||||
uint16_t DspCore::drawChar(uint16_t x, uint16_t y, uint16_t ch, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) {
|
||||
return cfont.width;
|
||||
}
|
||||
}
|
||||
return TFT_22_ILI9225::drawChar(x, y, ch, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,94 +1,31 @@
|
||||
#ifndef displayILI9225_h
|
||||
#define displayILI9225_h
|
||||
|
||||
#include "../core/options.h"
|
||||
//==================================================
|
||||
#include "Arduino.h"
|
||||
#include "../ILI9225Fix/TFT_22_ILI9225Fix.h"
|
||||
#include "fonts/DS_DIGI28pt7b.h"
|
||||
#include "fonts/DS_DIGI28pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define VU_READY 1
|
||||
#define WEATHER_READY 1
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#define TFT_FRAMEWDT 4
|
||||
#define META_SIZE 2
|
||||
#ifndef TITLE_SIZE1
|
||||
#define TITLE_SIZE1 1
|
||||
#endif
|
||||
#ifndef TITLE_SIZE2
|
||||
#define TITLE_SIZE2 1
|
||||
#endif
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 3
|
||||
#define SCROLLTIME 30
|
||||
typedef GFXcanvas16 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if __has_include("conf/displayILI9225conf_custom.h")
|
||||
#include "conf/displayILI9225conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayILI9225conf.h"
|
||||
#endif
|
||||
|
||||
#define PLMITEMS 9
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
#define TFT_FULLTIME 1
|
||||
#ifndef TITLE_TOP1
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + META_SIZE * TFT_LINEHGHT + 8
|
||||
#endif
|
||||
#ifndef TITLE_TOP2
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + (META_SIZE+2) * TFT_LINEHGHT
|
||||
#endif
|
||||
#define BOOT_PRG_COLOR 0xE68B
|
||||
#define BOOT_TXT_COLOR 0xFFFF
|
||||
#define PINK 0xF97F
|
||||
|
||||
class DspCore: public TFT_22_ILI9225 {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
void centerText(const char* text, uint16_t y, uint16_t fg, uint16_t bg);
|
||||
void rightText(const char* text, uint16_t y, uint16_t fg, uint16_t bg, bool fliprect=false, uint16_t delta = 0);
|
||||
void set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void setFont(uint8_t* font, bool monoSp=false );
|
||||
void setFont(const GFXfont *f = NULL);
|
||||
void setTextSize(uint8_t s);
|
||||
void setTextColor(uint16_t fg, uint16_t bg);
|
||||
void setCursor(int16_t x, int16_t y);
|
||||
uint16_t print(const char* s);
|
||||
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1,
|
||||
int16_t *y1, uint16_t *w, uint16_t *h);
|
||||
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
|
||||
uint16_t color);
|
||||
int16_t width(void) { return (int16_t)maxX(); }
|
||||
int16_t height(void) { return (int16_t)maxY(); }
|
||||
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t *bitmap, int16_t w, int16_t h);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
uint16_t bgcolor, fgcolor;
|
||||
int16_t cursorx, cursory;
|
||||
bool gFont, started;
|
||||
char oldTimeBuf[20];
|
||||
uint8_t oldVolume;
|
||||
uint16_t wot, hot;
|
||||
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ILI9341
|
||||
|
||||
#include "displayILI9341.h"
|
||||
#include <SPI.h>
|
||||
#include "fonts/bootlogo.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
|
||||
const char *dow[7] = {"вс","пн","вт","ср","чт","пт","сб"};
|
||||
const char *mnths[12] = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"};
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#define TAKE_MUTEX() if(player.mutex_pl) xSemaphoreTake(player.mutex_pl, portMAX_DELAY)
|
||||
#define GIVE_MUTEX() if(player.mutex_pl) xSemaphoreGive(player.mutex_pl)
|
||||
@@ -18,116 +14,18 @@ DspCore::DspCore(): Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST) {
|
||||
|
||||
}
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(TITLE_SIZE1);
|
||||
setTextColor(config.theme.title1, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, TITLE_TOP1);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TITLE_TOP2);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(config.theme.title2, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, sheight-TFT_FRAMEWDT-TFT_LINEHGHT*4);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight-TFT_FRAMEWDT-TFT_LINEHGHT*2);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
drawFastHLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, config.theme.div);
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
begin(); /* SPI_DEFAULT_FREQ 40000000 */
|
||||
invert();
|
||||
cp437(true);
|
||||
// fillScreen(config.theme.background);
|
||||
flip();
|
||||
setTextWrap(false);
|
||||
setTextSize(1);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
fillScreen(0x0000);
|
||||
drawRGBBitmap((swidth - 99) / 2, (sheight-64)/2 - TFT_LINEHGHT*2, bootlogo2, 99, 64);
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
drawRGBBitmap((width() - 99) / 2, top, bootlogo2, 99, 64);
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
@@ -136,223 +34,102 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 5, PLMITEMS);
|
||||
setTextSize(2);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) - 1, swidth, PLMITEMHEIGHT + 2, config.theme.meta);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
//fillRect(0, (height() / 2 - PLMITEMHEIGHT / 2) - 1, width(), PLMITEMHEIGHT + 2, config.theme.meta);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 5) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setTextColor(config.theme.playlist[abs(i - 5)-1], config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT-1, swidth, PLMITEMHEIGHT-4, config.theme.background);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT-1, width(), PLMITEMHEIGHT-4, config.theme.background);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
fillScreen(config.theme.background);
|
||||
void DspCore::clearDsp(bool black) { fillScreen(black?0:config.theme.background); }
|
||||
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT==0) return;
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI42pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, uint16_t y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
if(y==90) y=(sheight-64)/2 + 64 + TFT_LINEHGHT;
|
||||
if(y==110) y=(sheight-64)/2 + 64 + TFT_LINEHGHT*3;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect((swidth-w)/2-5, y, w+10, h, bg);
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, uint16_t y, uint16_t fg, uint16_t bg, bool fliprect, uint16_t delta) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT - delta, y);
|
||||
//fillRect(swidth - w - TFT_FRAMEWDT, fliprect?y-h:y, w, h, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT * 2 - 2;
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.heap, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, config.theme.background);
|
||||
print(ESP.getFreeHeap());
|
||||
print(" / ");
|
||||
print(ESP.getMaxAllocHeap());
|
||||
// audio buffer;
|
||||
fillRect(0, sheight - 2, swidth, 2, config.theme.background);
|
||||
int astored = player.inBufferFilled();
|
||||
int afree = player.inBufferFree();
|
||||
int aprcnt = 100 * astored / (astored + afree);
|
||||
uint16_t sbw = map(aprcnt, 0, 100 , 0, swidth);
|
||||
fillRect(0, sheight - 2, sbw, 2, config.theme.buffer);
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
|
||||
}
|
||||
|
||||
uint16_t cltop = 0;
|
||||
uint8_t clsp = 24;
|
||||
uint16_t clleft = 0;
|
||||
uint16_t clwidth = 0;
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
|
||||
char timeBuf[50] = { 0 };
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H:%M", &timeinfo);
|
||||
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
|
||||
int16_t x1, y1;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x1, &y1, &wot, &hot);
|
||||
if(cltop==0){
|
||||
cltop=sheight-(TFT_FRAMEWDT * 2 + TFT_LINEHGHT + 38) - hot;
|
||||
}
|
||||
clwidth = wot+clsp+(swidth>240?46:34);
|
||||
clleft=swidth-TFT_FRAMEWDT-clwidth;
|
||||
//fillRect(swidth-TFT_FRAMEWDT-clwidth, cltop-hot, clwidth, hot+3, config.theme.background);
|
||||
setCursor(clleft, cltop);
|
||||
setTextColor(config.theme.background);
|
||||
print(oldTimeBuf);
|
||||
strlcpy(oldTimeBuf, timeBuf, 20);
|
||||
getTextBounds(timeBuf, 0, 0, &x1, &y1, &wot, &hot);
|
||||
clwidth = wot+clsp+(swidth>240?46:34);
|
||||
clleft=swidth-TFT_FRAMEWDT-clwidth;
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(clleft, cltop);
|
||||
print(timeBuf);
|
||||
|
||||
setFont();
|
||||
setTextSize(3);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(clleft+wot+clsp, cltop-hot+32);
|
||||
print(utf8Rus(dow[timeinfo.tm_wday], false));
|
||||
|
||||
sprintf(timeBuf, "%2d %s %d", timeinfo.tm_mday,mnths[timeinfo.tm_mon], timeinfo.tm_year+1900);
|
||||
setTextSize(1);
|
||||
uint16_t wdate, hdate;
|
||||
getTextBounds(timeBuf, 0, 0, &x1, &y1, &wdate, &hdate);
|
||||
fillRect(swidth - wdate - TFT_FRAMEWDT-20, cltop+10, wdate+20, hdate, config.theme.background);
|
||||
rightText(utf8Rus(timeBuf,true), cltop+10, config.theme.date, config.theme.background, false, swidth>240?12:0);
|
||||
drawFastVLine(clleft+wot+clsp/2+3, cltop-hot, hot+3, config.theme.div);
|
||||
drawFastHLine(clleft+wot+clsp/2+3, cltop-hot+29, 42, config.theme.div);
|
||||
|
||||
drawFastHLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, config.theme.div);
|
||||
}
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(3);
|
||||
setTextColor(config.theme.seconds, config.theme.background);
|
||||
setCursor(clleft+wot+clsp, cltop-hot+1);
|
||||
sprintf(timeBuf, "%02d", timeinfo.tm_sec);
|
||||
print(timeBuf);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*3*2, clockTop-clockTimeHeight+1);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds); /* print seconds */
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2;
|
||||
int16_t volTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT *2;
|
||||
uint16_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, config.theme.background);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop - 1, ww, 5, config.theme.volbarin);
|
||||
drawRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, config.theme.volbarout);
|
||||
if(swidth>240){
|
||||
char buf[20];
|
||||
sprintf(buf, "VOL %d", config.store.volume);
|
||||
setTextSize(1);
|
||||
centerText(buf, volTop, config.theme.vol, config.theme.background);
|
||||
}
|
||||
if (withNumber) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
|
||||
/*setTextColor(config.theme.background);
|
||||
sprintf(volstr, "%d", oldVolume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(volstr);*/
|
||||
sprintf(volstr, "%d", oldVolume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect((swidth - wv) / 2 - 12, (sheight-hv)/2, wv+24, hv+4, config.theme.background);
|
||||
|
||||
setTextColor(config.theme.vol);
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
//fillRect(TFT_FRAMEWDT, (sheight-hv)/2, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(volstr);
|
||||
oldVolume=config.store.volume;
|
||||
setFont();
|
||||
}
|
||||
void DspCore::_clockDate(){
|
||||
if(_olddateleft>0)
|
||||
dsp.fillRect(_olddateleft, clockTop+10, _olddatewidth, CHARHEIGHT, config.theme.background);
|
||||
setTextColor(config.theme.date, config.theme.background);
|
||||
setCursor(_dateleft, clockTop+10);
|
||||
print(_dateBuf); /* print date */
|
||||
strlcpy(_oldDateBuf, _dateBuf, sizeof(_dateBuf));
|
||||
_olddatewidth = _datewidth;
|
||||
_olddateleft = _dateleft;
|
||||
setTextSize(3);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*3*2, clockTop-CHARHEIGHT*3+4);
|
||||
print(utf8Rus(dow[network.timeinfo.tm_wday], false)); /* print dow */
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = width()-clockRightSpace-CHARWIDTH*3*2-24-_timewidth;
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, (sheight-hv)/2, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(numstr);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
drawFastVLine(width()-clockRightSpace-CHARWIDTH*3*2-18, clockTop-clockTimeHeight, clockTimeHeight+3, config.theme.div); /*divider vert*/
|
||||
drawFastHLine(width()-clockRightSpace-CHARWIDTH*3*2-18, clockTop-clockTimeHeight+29, 44, config.theme.div); /*divider hor*/
|
||||
sprintf(_buffordate, "%2d %s %d", network.timeinfo.tm_mday,mnths[network.timeinfo.tm_mon], network.timeinfo.tm_year+1900);
|
||||
strlcpy(_dateBuf, utf8Rus(_buffordate, true), sizeof(_dateBuf));
|
||||
_datewidth = strlen(_dateBuf) * CHARWIDTH;
|
||||
_dateleft = width() - 8 - clockRightSpace - _datewidth;
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(META_SIZE);
|
||||
centerText(str, TFT_FRAMEWDT, config.theme.meta, config.theme.background);
|
||||
drawFastHLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, config.theme.div);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
if(strcmp(_oldDateBuf, _dateBuf)!=0 || redraw) _clockDate();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
char buf[20];
|
||||
sprintf(buf, "RSSI:%s", str);
|
||||
setTextSize(1);
|
||||
rightText(buf, vTop, config.theme.rssi, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
char buf[30];
|
||||
sprintf(buf, "IP: %s", str);
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.ip, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
print(buf);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*3*2+24, clockTimeHeight+10+CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::startWrite(void) {
|
||||
@@ -365,25 +142,17 @@ void DspCore::endWrite(void) {
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::loop(bool force) { }
|
||||
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
}
|
||||
void DspCore::flip(){
|
||||
setRotation(config.store.flipscreen?1:3);
|
||||
}
|
||||
@@ -395,4 +164,31 @@ void DspCore::invert(){
|
||||
void DspCore::sleep(void) { sendCommand(ILI9341_SLPIN); delay(150); sendCommand(ILI9341_DISPOFF); delay(150);}
|
||||
void DspCore::wake(void) { sendCommand(ILI9341_DISPON); delay(150); sendCommand(ILI9341_SLPOUT); delay(150);}
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_ILI9341::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_ILI9341::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,76 +1,32 @@
|
||||
#ifndef displayILI9341_h
|
||||
#define displayILI9341_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_ILI9341.h>
|
||||
// https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "fonts/DS_DIGI42pt7b.h"
|
||||
#include "fonts/DS_DIGI42pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define VU_READY 1
|
||||
#define WEATHER_READY 1
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#define TFT_FRAMEWDT 8
|
||||
#define META_SIZE 3
|
||||
#define TITLE_SIZE1 2
|
||||
#define TITLE_SIZE2 2
|
||||
typedef GFXcanvas16 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 4
|
||||
#define SCROLLTIME 30
|
||||
#if __has_include("conf/displayILI9341conf_custom.h")
|
||||
#include "conf/displayILI9341conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayILI9341conf.h"
|
||||
#endif
|
||||
|
||||
#define PLMITEMS 11
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
#define TFT_FULLTIME 1
|
||||
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + META_SIZE * TFT_LINEHGHT + 8
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + (META_SIZE+2) * TFT_LINEHGHT + 8
|
||||
#define BOOT_PRG_COLOR 0xE68B
|
||||
#define BOOT_TXT_COLOR 0xFFFF
|
||||
#define PINK 0xF97F
|
||||
|
||||
class DspCore: public Adafruit_ILI9341 {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
void centerText(const char* text, uint16_t y, uint16_t fg, uint16_t bg);
|
||||
void rightText(const char* text, uint16_t y, uint16_t fg, uint16_t bg, bool fliprect=false, uint16_t delta = 0);
|
||||
void set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
virtual void startWrite(void);
|
||||
virtual void endWrite(void);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
char oldTimeBuf[20];
|
||||
uint8_t oldVolume;
|
||||
uint16_t wot, hot;
|
||||
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
@@ -1,227 +1,153 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
|
||||
#if DSP_MODEL==DSP_1602I2C || DSP_MODEL==DSP_1602 || DSP_MODEL==DSP_2004 || DSP_MODEL==DSP_2004I2C
|
||||
|
||||
#include "displayLC1602.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef SCREEN_ADDRESS
|
||||
#define SCREEN_ADDRESS 0x27 ///< See datasheet for Address or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#endif
|
||||
|
||||
#ifdef LCD_2004
|
||||
const byte controlspaces[] = { CLOCK_SPACE, 0, 0, VOL_SPACE };
|
||||
#else
|
||||
const byte controlspaces[] = { CLOCK_SPACE, VOL_SPACE };
|
||||
#define SCREEN_ADDRESS 0x27 ///< See datasheet for Address or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#endif
|
||||
|
||||
DspCore::DspCore(): DSP_INIT {}
|
||||
|
||||
#include "tools/utf8RusLCD.h"
|
||||
|
||||
void DspCore::apScreen() {
|
||||
clear();
|
||||
setCursor(0,0);
|
||||
print("YORADIO AP MODE");
|
||||
print(utf8Rus(const_lcdApMode, false));
|
||||
setCursor(0,1);
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
#ifdef LCD_2004
|
||||
setCursor(0, 2);
|
||||
print("AP NAME: ");
|
||||
print(utf8Rus(const_lcdApName, false));
|
||||
print(apSsid);
|
||||
setCursor(0, 3);
|
||||
print("PASSWORD: ");
|
||||
print(utf8Rus(const_lcdApPass, false));
|
||||
print(apPassword);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
byte Arrow[] PROGMEM = { B00000, B00100, B00010, B01001, B00010, B00100, B00000, B00000 };
|
||||
|
||||
void DspCore::initDisplay() {
|
||||
#ifdef LCD_I2C
|
||||
init();
|
||||
backlight();
|
||||
#else
|
||||
#ifdef LCD_2004
|
||||
begin(20, 4);
|
||||
#else
|
||||
begin(16, 2);
|
||||
#ifdef LCD_2004
|
||||
begin(20, 4);
|
||||
#else
|
||||
begin(16, 2);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LCD_2004
|
||||
screenwidth = 20;
|
||||
screenheight = 4;
|
||||
#else
|
||||
screenwidth = 16;
|
||||
screenheight = 2;
|
||||
#endif
|
||||
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
fillSpaces = true;
|
||||
clearClipping();
|
||||
createChar(0, Arrow);
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
void DspCore::drawLogo(uint16_t top) { }
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
centerText("NEXT STATION", 0, 0, 0);
|
||||
clear();
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
plMenu[i][0] = '\0';
|
||||
}
|
||||
#ifdef LCD_2004
|
||||
config.fillPlMenu(plMenu, currentItem-1, PLMITEMS);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 1) {
|
||||
strlcpy(currentItemText, ">", 2);
|
||||
//strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
strlcat(currentItemText, plMenu[i], PLMITEMLENGHT - 2);
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
char tmp[swidth+1] = {0};
|
||||
strlcpy(tmp, utf8Rus(plMenu[i], true), swidth);
|
||||
clearScroll(1 + i, 0, 0);
|
||||
setCursor(1, 1 + i);
|
||||
char tmp[width()] = {0};
|
||||
strlcpy(tmp, utf8Rus(plMenu[i], true), width());
|
||||
setCursor(1, i);
|
||||
print(tmp);
|
||||
}
|
||||
}
|
||||
#else
|
||||
config.fillPlMenu(plMenu, currentItem, PLMITEMS);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
}
|
||||
#endif
|
||||
setCursor(0,1);
|
||||
write(byte(0));
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
void DspCore::clearDsp(bool black) {
|
||||
clear();
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
tWidth = strlen(text);
|
||||
tHeight = 1;
|
||||
sWidth = strlen(separator);
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
for(uint16_t x=0; x<swidth-(fillSpaces?controlspaces[texttop]:0); x++){
|
||||
setCursor(x, texttop);
|
||||
print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
byte x=(strlen(text)>swidth)?0:(swidth-strlen(text))/2;
|
||||
void DspCore::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
|
||||
if(w<2) return;
|
||||
char buf[width()+1] = { 0 };
|
||||
snprintf(buf, sizeof(buf), "%*s%s", w-1, "", " ");
|
||||
setCursor(x, y);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
byte x=swidth-strlen(text);
|
||||
setCursor(x-1, y);
|
||||
print(" ");
|
||||
print(buf);
|
||||
setCursor(x, y);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
rightText(timestr, 0, 0, 0);
|
||||
}
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
char volstr[4];
|
||||
sprintf(volstr, "%02d", config.store.volume);
|
||||
if (withNumber) {;
|
||||
centerText(" ", 1, 0, 0);
|
||||
centerText(volstr, 1, TFT_LOGO, TFT_BG);
|
||||
}else{
|
||||
uint16_t DspCore::width(){
|
||||
#ifdef LCD_2004
|
||||
rightText(" ", 3, 0, 0);
|
||||
rightText(volstr, 3, TFT_LOGO, TFT_BG);
|
||||
return 20;
|
||||
#else
|
||||
rightText(" ", 1, 0, 0);
|
||||
rightText(volstr, 1, TFT_LOGO, TFT_BG);
|
||||
return 16;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
char numstr[7];
|
||||
sprintf(numstr, "%d", num);
|
||||
clearScroll(1, 0, 0);
|
||||
centerText(numstr, 1, TFT_LOGO, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
uint16_t DspCore::height(){
|
||||
#ifdef LCD_2004
|
||||
setCursor(0, 3);
|
||||
print(str);
|
||||
return 4;
|
||||
#else
|
||||
return 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
if(x<0) {
|
||||
xOffset=-x;
|
||||
x=0;
|
||||
}else{
|
||||
xOffset=0;
|
||||
void DspCore::_getTimeBounds() { }
|
||||
|
||||
void DspCore::_clockSeconds(){
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print((network.timeinfo.tm_sec % 2 == 0)?":":" ");
|
||||
}
|
||||
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
void DspCore::_clockTime(){ }
|
||||
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw) {
|
||||
clockTop = 0;
|
||||
_timeleft = width()-5;
|
||||
_dotsLeft = 2;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
}
|
||||
nextX=0;
|
||||
yOffset = y;
|
||||
setCursor(x, y);
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
char tmp[swidth+1] = {0};
|
||||
int16_t numchars = fillSpaces?swidth-controlspaces[yOffset]:swidth;
|
||||
strlcpy(tmp, txt+xOffset, numchars+1-nextX);
|
||||
print(tmp);
|
||||
xOffset=(int16_t)(strlen(txt)-xOffset)<=0?xOffset-strlen(txt):0;
|
||||
nextX=nextX+strlen(tmp);
|
||||
if(nextX>numchars) nextX=numchars;
|
||||
setCursor(nextX, yOffset);
|
||||
void DspCore::clearClock() { }
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
// delay(100);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
if (checkdelay(SCROLLTIME, loopdelay)) {
|
||||
//display();
|
||||
}
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = 1;
|
||||
height = 1;
|
||||
}
|
||||
|
||||
boolean DspCore::checkdelay(int m, unsigned long & tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void DspCore::flip(){ }
|
||||
|
||||
void DspCore::invert(){ }
|
||||
|
||||
void DspCore::sleep(void) {
|
||||
noDisplay();
|
||||
@@ -236,111 +162,20 @@ void DspCore::wake(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
static char newStr[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
newStr[0] = '\0';
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) { }
|
||||
|
||||
while (strn[index])
|
||||
{
|
||||
if (strlen(newStr) > BUFLEN - 2) break;
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
switch (strn[index + 1])
|
||||
{
|
||||
case 0x90: strcat(newStr, "A"); break;
|
||||
case 0x91: strcat(newStr, "B"); break;
|
||||
case 0x92: strcat(newStr, "V"); break;
|
||||
case 0x93: strcat(newStr, "G"); break;
|
||||
case 0x94: strcat(newStr, "D"); break;
|
||||
case 0x95: strcat(newStr, "E"); break;
|
||||
case 0x96: strcat(newStr, "ZH"); break;
|
||||
case 0x97: strcat(newStr, "Z"); break;
|
||||
case 0x98: strcat(newStr, "I"); break;
|
||||
case 0x99: strcat(newStr, "Y"); break;
|
||||
case 0x9A: strcat(newStr, "K"); break;
|
||||
case 0x9B: strcat(newStr, "L"); break;
|
||||
case 0x9C: strcat(newStr, "M"); break;
|
||||
case 0x9D: strcat(newStr, "N"); break;
|
||||
case 0x9E: strcat(newStr, "O"); break;
|
||||
case 0x9F: strcat(newStr, "P"); break;
|
||||
case 0xA0: strcat(newStr, "R"); break;
|
||||
case 0xA1: strcat(newStr, "S"); break;
|
||||
case 0xA2: strcat(newStr, "T"); break;
|
||||
case 0xA3: strcat(newStr, "U"); break;
|
||||
case 0xA4: strcat(newStr, "F"); break;
|
||||
case 0xA5: strcat(newStr, "H"); break;
|
||||
case 0xA6: strcat(newStr, "TS"); break;
|
||||
case 0xA7: strcat(newStr, "CH"); break;
|
||||
case 0xA8: strcat(newStr, "SH"); break;
|
||||
case 0xA9: strcat(newStr, "SHCH"); break;
|
||||
case 0xAA: strcat(newStr, "'"); break;
|
||||
case 0xAB: strcat(newStr, "YU"); break;
|
||||
case 0xAC: strcat(newStr, "'"); break;
|
||||
case 0xAD: strcat(newStr, "E"); break;
|
||||
case 0xAE: strcat(newStr, "YU"); break;
|
||||
case 0xAF: strcat(newStr, "YA"); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
strcat(newStr, "YO"); break;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
} else {
|
||||
char Temp[2] = {(char) strn[index] , 0 } ;
|
||||
strcat(newStr, Temp);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return newStr;
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { }
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
setClipping({0, 0, width(), height()});
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){ }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,121 +1,76 @@
|
||||
#ifndef displayLC1602_h
|
||||
#define displayLC1602_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define DSP_FLIPPED 0
|
||||
#define DSP_NOT_FLIPPED
|
||||
#define DSP_LCD
|
||||
|
||||
#define CHARWIDTH 1
|
||||
#define CHARHEIGHT 1
|
||||
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if DSP_MODEL==DSP_2004 || DSP_MODEL==DSP_2004I2C
|
||||
#define LCD_2004
|
||||
#define LCD_2004
|
||||
#endif
|
||||
|
||||
#if DSP_MODEL==DSP_1602I2C || DSP_MODEL==DSP_2004I2C
|
||||
#define LCD_I2C
|
||||
#include "../LiquidCrystalI2C/LiquidCrystalI2CEx.h"
|
||||
#define LCD_I2C
|
||||
#include "../LiquidCrystalI2C/LiquidCrystalI2CEx.h"
|
||||
#else
|
||||
#include <LiquidCrystal.h>
|
||||
#include <LiquidCrystal.h>
|
||||
#endif
|
||||
|
||||
#ifdef LCD_I2C
|
||||
#ifdef LCD_2004
|
||||
#define DSP_INIT LiquidCrystal_I2C(SCREEN_ADDRESS, 20, 4, I2C_SDA, I2C_SCL)
|
||||
#else
|
||||
#define DSP_INIT LiquidCrystal_I2C(SCREEN_ADDRESS, 16, 2, I2C_SDA, I2C_SCL)
|
||||
#endif
|
||||
#else
|
||||
#define DSP_INIT LiquidCrystal(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7)
|
||||
#endif
|
||||
|
||||
#ifdef LCD_2004
|
||||
#define DSP_INIT LiquidCrystal_I2C(SCREEN_ADDRESS, 20, 4, I2C_SDA, I2C_SCL)
|
||||
#if __has_include("conf/displayLCD2004conf_custom.h")
|
||||
#include "conf/displayLCD2004conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayLCD2004conf.h"
|
||||
#endif
|
||||
#else
|
||||
#define DSP_INIT LiquidCrystal_I2C(SCREEN_ADDRESS, 16, 2, I2C_SDA, I2C_SCL)
|
||||
#endif
|
||||
#else
|
||||
#define DSP_INIT LiquidCrystal(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7)
|
||||
#if __has_include("conf/displayLCD1602conf_custom.h")
|
||||
#include "conf/displayLCD1602conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayLCD1602conf.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BOOT_PRG_COLOR 0x1
|
||||
#define BOOT_TXT_COLOR 0x1
|
||||
#define PINK 0x1
|
||||
|
||||
#define TFT_LINEHGHT 1
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define DSP_CAN_SLEEP true
|
||||
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 9
|
||||
#define TITLE_TOP1 1
|
||||
#ifdef LCD_2004
|
||||
#define PLMITEMS 3
|
||||
#define TITLE_TOP2 2
|
||||
#define PL_TOP 2
|
||||
#define BOOTSTR_TOP2 1
|
||||
#define BOOTSTR_TOP1 2
|
||||
#else
|
||||
#define PLMITEMS 1
|
||||
#define TITLE_SIZE2 0
|
||||
#define IP_INST_VOL
|
||||
#define PL_TOP 1
|
||||
#define BOOTSTR_TOP2 0
|
||||
#define BOOTSTR_TOP1 1
|
||||
#endif
|
||||
|
||||
#define PLCURRENT_SIZE 1
|
||||
|
||||
#define SCROLLDELTA 1
|
||||
#define SCROLLTIME 250
|
||||
|
||||
|
||||
#define STARTTIME_PL 2000
|
||||
/* not used required */
|
||||
#define bootLogoTop 0
|
||||
const char rssiFmt[] PROGMEM = "";
|
||||
const MoveConfig clockMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 0, 0, -1 };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 0, 0, -1 };
|
||||
const char const_lcdApMode[] PROGMEM = "YORADIO AP MODE";
|
||||
const char const_lcdApName[] PROGMEM = "AP NAME: ";
|
||||
const char const_lcdApPass[] PROGMEM = "PASSWORD: ";
|
||||
|
||||
#ifdef LCD_I2C
|
||||
class DspCore: public LiquidCrystal_I2C {
|
||||
class DspCore: public LiquidCrystal_I2C {
|
||||
#else
|
||||
class DspCore: public LiquidCrystal {
|
||||
class DspCore: public LiquidCrystal {
|
||||
#endif
|
||||
public:
|
||||
bool fillSpaces;
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase=true);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void flip(){};
|
||||
void invert(){};
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight, xOffset, yOffset;
|
||||
int16_t nextX;
|
||||
unsigned long loopdelay;
|
||||
boolean checkdelay(int m, unsigned long &tstamp);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
/*
|
||||
* TFT COLORS
|
||||
*/
|
||||
#define CLOCK_SPACE 6
|
||||
#ifdef LCD_2004
|
||||
#define VOL_SPACE 0
|
||||
#else
|
||||
#define VOL_SPACE 3
|
||||
#endif
|
||||
#define SILVER 0
|
||||
#define TFT_BG 0
|
||||
#define TFT_FG CLOCK_SPACE
|
||||
#define TFT_LOGO VOL_SPACE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==3
|
||||
|
||||
#include "displayN5110.h"
|
||||
#include <Wire.h>
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#define LOGO_WIDTH 21
|
||||
#define LOGO_HEIGHT 28
|
||||
@@ -27,98 +27,7 @@ DspCore::DspCore(): Adafruit_PCD8544(TFT_DC, TFT_CS, TFT_RST) {
|
||||
|
||||
}
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
setFont(&TinyFont6);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 1 * TFT_LINEHGHT+6);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 2 * TFT_LINEHGHT+6);
|
||||
print("PASSWD: ");
|
||||
print(apPassword);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, sheight - 10);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight-2);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
setFont();
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::command(uint8_t c) {
|
||||
TAKE_MUTEX();
|
||||
@@ -132,30 +41,35 @@ void DspCore::data(uint8_t c) {
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
begin();
|
||||
setReinitInterval(255);
|
||||
config.theme.background = TFT_BG;
|
||||
config.theme.meta = TFT_FG;
|
||||
config.theme.clock = TFT_FG;
|
||||
config.theme.weather = TFT_FG;
|
||||
config.theme.metabg = TFT_BG;
|
||||
config.theme.metafill = TFT_BG;
|
||||
config.theme.title1 = TFT_FG;
|
||||
config.theme.title2 = TFT_FG;
|
||||
config.theme.rssi = TFT_FG;
|
||||
config.theme.ip = TFT_FG;
|
||||
config.theme.bitrate = TFT_FG;
|
||||
config.theme.digit = TFT_FG;
|
||||
config.theme.buffer = TFT_FG;
|
||||
config.theme.volbarout = TFT_FG;
|
||||
config.theme.volbarin = TFT_FG;
|
||||
for(byte i=0;i<5;i++) config.theme.playlist[i] = TFT_FG;
|
||||
|
||||
setContrast(config.store.contrast);
|
||||
cp437(true);
|
||||
invert();
|
||||
fillScreen(TFT_BG);
|
||||
flip();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
clearDisplay();
|
||||
drawBitmap((width() - LOGO_WIDTH ) / 2, 0, logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
drawBitmap((width() - LOGO_WIDTH ) / 2, top, logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
display();
|
||||
}
|
||||
|
||||
@@ -165,185 +79,108 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 3, PLMITEMS);
|
||||
setTextSize(1);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) + 1, swidth, PLMITEMHEIGHT, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 3) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, swidth, PLMITEMHEIGHT - 1, TFT_BG);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, width(), PLMITEMHEIGHT - 1, TFT_BG);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT == 0) return;
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI15pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
|
||||
if(y==90) {
|
||||
y=sheight-TFT_LINEHGHT*2;
|
||||
}
|
||||
if(y==110) {
|
||||
y=sheight;
|
||||
setFont(&TinyFont5);
|
||||
}
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(utf8Rus(txt, true));
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y+h+1);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, y, w, h+1, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI15pt7b);
|
||||
getTextBounds(timestr, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(TFT_FG);
|
||||
setCursor((swidth - w) / 2, 19+17);
|
||||
fillRect(0, 18, swidth, h+2, TFT_BG);
|
||||
print(timestr);
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - 3;
|
||||
int16_t vWidth = swidth;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_BG);
|
||||
drawRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_LOGO);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop + 1, ww, 1, TFT_LOGO);
|
||||
if (withNumber) {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
setFont(&DS_DIGI15pt7b);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 24-10, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 24+8);
|
||||
print(volstr);
|
||||
setFont();
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
setFont(&DS_DIGI15pt7b);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 24-10, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 24+8);
|
||||
print(numstr);
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(1);
|
||||
centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strlcpy(buf, str, strlen(str)-2);
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - 2;
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(1);
|
||||
setFont(&TinyFont5);
|
||||
rightText(buf, vTop, SILVER, TFT_BG);
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - 2;
|
||||
setFont(&DS_DIGI15pt7b);
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":");
|
||||
setFont(); /* print dots */
|
||||
setTextSize(1);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(0, vTop);
|
||||
setFont(&TinyFont5);
|
||||
print(str);
|
||||
setCursor(_timeleft+_timewidth+2, clockTop-CHARHEIGHT*2-1);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds);
|
||||
}
|
||||
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth+CHARWIDTH*2+2, clockTimeHeight, config.theme.background);
|
||||
//if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = (width()/2 - _timewidth/2)-clockRightSpace;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI15pt7b);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*2+2, clockTimeHeight, config.theme.background);
|
||||
//dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*3*2+24, clockTimeHeight+10+CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
if (checkdelay(SCROLLTIME, loopdelay) || force) {
|
||||
display();
|
||||
}
|
||||
display();
|
||||
delay(5);
|
||||
}
|
||||
|
||||
boolean DspCore::checkdelay(int m, unsigned long &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
setRotation(config.store.flipscreen?2:0);
|
||||
}
|
||||
@@ -355,4 +192,32 @@ void DspCore::invert(){
|
||||
void DspCore::sleep(void) { command( PCD8544_FUNCTIONSET | PCD8544_POWERDOWN); }
|
||||
void DspCore::wake(void) { initDisplay(); }
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_PCD8544::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_PCD8544::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI15pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifndef displayN5110_h
|
||||
#define displayN5110_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
@@ -7,68 +8,25 @@
|
||||
#include "fonts/TinyFont5.h"
|
||||
#include "fonts/TinyFont6.h"
|
||||
#include "fonts/DS_DIGI15pt7b.h"
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define TFT_LINEHGHT 8
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define DSP_OLED true
|
||||
#define DSP_OLED
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
//#define SCROLLDELTA 8
|
||||
//#define SCROLLTIME 332
|
||||
#define SCROLLDELTA 4
|
||||
#define SCROLLTIME 250
|
||||
typedef GFXcanvas1 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if __has_include("conf/displayN5110conf_custom.h")
|
||||
#include "conf/displayN5110conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayN5110conf.h"
|
||||
#endif
|
||||
|
||||
#define META_SIZE 1
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + TFT_LINEHGHT+1
|
||||
#define TITLE_SIZE2 0
|
||||
#define PLCURRENT_SIZE 1
|
||||
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
|
||||
class DspCore: public Adafruit_PCD8544 {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
virtual void command(uint8_t c);
|
||||
virtual void data(uint8_t c);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
unsigned long loopdelay;
|
||||
boolean checkdelay(int m, unsigned long &tstamp);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
@@ -76,9 +34,11 @@ extern DspCore dsp;
|
||||
/*
|
||||
* TFT COLORS
|
||||
*/
|
||||
#define SILVER BLACK
|
||||
#define TFT_BG WHITE
|
||||
#define TFT_FG BLACK
|
||||
#define TFT_LOGO BLACK
|
||||
#define BOOT_PRG_COLOR BLACK
|
||||
#define BOOT_TXT_COLOR BLACK
|
||||
#define SILVER BLACK
|
||||
#define TFT_BG WHITE
|
||||
#define TFT_FG BLACK
|
||||
#define TFT_LOGO BLACK
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_SH1106 || DSP_MODEL==DSP_SH1107
|
||||
|
||||
#include "displaySH1106.h"
|
||||
#include <Wire.h>
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef SCREEN_ADDRESS
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#endif
|
||||
|
||||
#define LOGO_WIDTH 21
|
||||
#define LOGO_HEIGHT 32
|
||||
|
||||
#ifndef I2CFREQ_HZ
|
||||
#define I2CFREQ_HZ 4000000UL
|
||||
#define I2CFREQ_HZ 4000000UL
|
||||
#endif
|
||||
|
||||
const char *dow[7] = {"вс","пн","вт","ср","чт","пт","сб"};
|
||||
|
||||
const unsigned char logo [] PROGMEM=
|
||||
{
|
||||
0x06, 0x03, 0x00, 0x0f, 0x07, 0x80, 0x1f, 0x8f, 0xc0, 0x1f, 0x8f, 0xc0,
|
||||
@@ -42,128 +40,42 @@ DspCore::DspCore(): Adafruit_SH1107(64, 128, &I2CSH1106, -1) {
|
||||
|
||||
}
|
||||
#endif
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 2 * TFT_LINEHGHT);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 3 * TFT_LINEHGHT);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT * 2);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
I2CSH1106.begin(I2C_SDA, I2C_SCL);
|
||||
if (!begin(SCREEN_ADDRESS, true)) {
|
||||
Serial.println(F("SH110X allocation failed"));
|
||||
for (;;); // Don't proceed, loop forever
|
||||
}
|
||||
config.theme.background = TFT_BG;
|
||||
config.theme.meta = TFT_FG;
|
||||
config.theme.meta = TFT_BG;
|
||||
config.theme.clock = TFT_FG;
|
||||
config.theme.weather = TFT_FG;
|
||||
config.theme.metabg = TFT_FG;
|
||||
config.theme.metafill = TFT_FG;
|
||||
config.theme.title1 = TFT_FG;
|
||||
config.theme.title2 = TFT_FG;
|
||||
config.theme.rssi = TFT_FG;
|
||||
config.theme.ip = TFT_FG;
|
||||
config.theme.vol = TFT_FG;
|
||||
config.theme.bitrate = TFT_FG;
|
||||
config.theme.digit = TFT_FG;
|
||||
config.theme.buffer = TFT_FG;
|
||||
config.theme.volbarout = TFT_FG;
|
||||
config.theme.volbarin = TFT_FG;
|
||||
|
||||
for(byte i=0;i<5;i++) config.theme.playlist[i] = TFT_FG;
|
||||
|
||||
cp437(true);
|
||||
fillScreen(TFT_BG);
|
||||
flip();
|
||||
invert();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
clearDisplay();
|
||||
drawBitmap(
|
||||
(width() - LOGO_WIDTH ) / 2,
|
||||
8,
|
||||
logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
display();
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
drawBitmap((width() - LOGO_WIDTH ) / 2, top, logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
@@ -172,184 +84,100 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 3, PLMITEMS);
|
||||
setTextSize(1);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) + 1, swidth, PLMITEMHEIGHT, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 3) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, swidth, PLMITEMHEIGHT - 1, TFT_BG);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, width(), PLMITEMHEIGHT - 1, TFT_BG);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
display();
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT == 0) return;
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
return CHARWIDTH*clockTimeHeight;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
if(y==90) y=sheight-TFT_LINEHGHT*2-5;
|
||||
if(y==110) y=sheight-TFT_LINEHGHT;
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(txt);
|
||||
display();
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, y, w, h, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
setTextSize(2);
|
||||
centerText(timestr, 34, TFT_FG, TFT_BG);
|
||||
setTextSize(1);
|
||||
}
|
||||
|
||||
#define CLCLF 34
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw) {
|
||||
char timeStringBuff[20] = { 0 };
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%H:%M", &timeinfo);
|
||||
setTextSize(2);
|
||||
setCursor(CLCLF, (DSP_MODEL==DSP_SH1107)?30:34);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
print(timeStringBuff);
|
||||
setTextSize(1);
|
||||
setCursor(CLCLF + 6*2*5+1, (DSP_MODEL==DSP_SH1107)?30+1:34+1);
|
||||
sprintf(timeStringBuff, "%02d", timeinfo.tm_sec);
|
||||
print(timeStringBuff);
|
||||
display();
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - 4;
|
||||
int16_t vWidth = swidth;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_BG);
|
||||
drawRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_LOGO);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop + 1, ww, 1, TFT_LOGO);
|
||||
if (withNumber) {
|
||||
setTextSize(2);
|
||||
setTextColor(TFT_FG);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 24, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);;
|
||||
setCursor((swidth - wv) / 2, 24);
|
||||
print(volstr);
|
||||
}
|
||||
display();
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(2);
|
||||
setTextColor(TFT_FG);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 24, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 24);
|
||||
print(numstr);
|
||||
display();
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(2);
|
||||
centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strlcpy(buf, str, strlen(str)-2);
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - 4;
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(clockTimeHeight);
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setTextSize(1);
|
||||
rightText(buf, vTop, SILVER, TFT_BG);
|
||||
setCursor(_timeleft+_timewidth+1, clockTop);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - 4;
|
||||
setTextSize(1);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(0, vTop);
|
||||
print(str);
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop, _oldtimewidth, clockTimeHeight*CHARHEIGHT, config.theme.background);
|
||||
_timeleft = (width()/2 - _timewidth/2)+clockRightSpace;
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setTextSize(clockTimeHeight);
|
||||
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop, _timewidth, clockTimeHeight*CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
void DspCore::startWrite(void) { }
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
display();
|
||||
}
|
||||
void DspCore::endWrite(void) { }
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
if (checkdelay(SCROLLTIME, loopdelay) || force) {
|
||||
//display();
|
||||
}
|
||||
display();
|
||||
delay(5);
|
||||
}
|
||||
|
||||
boolean DspCore::checkdelay(int m, unsigned long &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
#if DSP_MODEL==DSP_SH1107
|
||||
setRotation(config.store.flipscreen?3:1);
|
||||
@@ -366,4 +194,39 @@ void DspCore::invert(){
|
||||
void DspCore::sleep(void) { oled_command(SH110X_DISPLAYOFF); }
|
||||
void DspCore::wake(void) { oled_command(SH110X_DISPLAYON); }
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
#if DSP_MODEL==DSP_SH1107
|
||||
Adafruit_SH1107::writePixel(x, y, color);
|
||||
#else
|
||||
Adafruit_SH1106G::writePixel(x, y, color);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
#if DSP_MODEL==DSP_SH1107
|
||||
Adafruit_SH1107::writeFillRect(x, y, w, h, color);
|
||||
#else
|
||||
Adafruit_SH1106G::writeFillRect(x, y, w, h, color);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setTextSize(2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
#ifndef displaySH1106_h
|
||||
#define displaySH1106_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SH110X.h>
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define TFT_LINEHGHT 8
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define DSP_OLED true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + 3 * TFT_LINEHGHT
|
||||
#define PLCURRENT_SIZE 1
|
||||
#define TFT_FULLTIME 1
|
||||
#define DSP_OLED
|
||||
|
||||
#if DSP_MODEL==DSP_SH1107
|
||||
#define TITLE_SIZE2 0
|
||||
#endif
|
||||
typedef GFXcanvas1 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 2
|
||||
#define SCROLLTIME 35
|
||||
#if __has_include("conf/displaySH1106conf_custom.h")
|
||||
#include "conf/displaySH1106conf_custom.h"
|
||||
#else
|
||||
#include "conf/displaySH1106conf.h"
|
||||
#endif
|
||||
|
||||
#if DSP_MODEL==DSP_SH1106
|
||||
@@ -31,52 +27,20 @@ class DspCore: public Adafruit_SH1106G {
|
||||
#else
|
||||
class DspCore: public Adafruit_SH1107 {
|
||||
#endif
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
unsigned long loopdelay;
|
||||
boolean checkdelay(int m, unsigned long &tstamp);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
/*
|
||||
* TFT COLORS
|
||||
* OLED COLORS
|
||||
*/
|
||||
#define SILVER SH110X_WHITE
|
||||
#define TFT_BG SH110X_BLACK
|
||||
#define TFT_FG SH110X_WHITE
|
||||
#define TFT_LOGO SH110X_WHITE
|
||||
#define BOOT_PRG_COLOR SH110X_WHITE
|
||||
#define BOOT_TXT_COLOR SH110X_WHITE
|
||||
#define PINK SH110X_WHITE
|
||||
#define SILVER SH110X_WHITE
|
||||
#define TFT_BG SH110X_BLACK
|
||||
#define TFT_FG SH110X_WHITE
|
||||
#define TFT_LOGO SH110X_WHITE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_SSD1305 || DSP_MODEL==DSP_SSD1305I2C
|
||||
|
||||
#include "displaySSD1305.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef SCREEN_ADDRESS
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#endif
|
||||
|
||||
#define LOGO_WIDTH 21
|
||||
#define LOGO_HEIGHT 32
|
||||
|
||||
#ifndef DEF_SPI_FREQ
|
||||
#define DEF_SPI_FREQ 8000000UL /* set it to 0 for system default */
|
||||
#define DEF_SPI_FREQ 8000000UL /* set it to 0 for system default */
|
||||
#endif
|
||||
|
||||
const char *dow[7] = {"вс","пн","вт","ср","чт","пт","сб"};
|
||||
|
||||
const unsigned char logo [] PROGMEM=
|
||||
{
|
||||
0x06, 0x03, 0x00, 0x0f, 0x07, 0x80, 0x1f, 0x8f, 0xc0, 0x1f, 0x8f, 0xc0,
|
||||
@@ -42,99 +40,10 @@ DspCore::DspCore(): Adafruit_SSD1305(128, 64, &I2CSSD1305, -1){
|
||||
|
||||
}
|
||||
#endif
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 2 * TFT_LINEHGHT);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 3 * TFT_LINEHGHT);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT * 2);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
#if DSP_MODEL==DSP_SSD1305I2C
|
||||
I2CSSD1305.begin(I2C_SDA, I2C_SCL);
|
||||
#endif
|
||||
@@ -143,28 +52,32 @@ void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
for (;;); // Don't proceed, loop forever
|
||||
}
|
||||
config.theme.background = TFT_BG;
|
||||
config.theme.meta = TFT_FG;
|
||||
config.theme.meta = TFT_BG;
|
||||
config.theme.clock = TFT_FG;
|
||||
config.theme.weather = TFT_FG;
|
||||
config.theme.metabg = TFT_FG;
|
||||
config.theme.metafill = TFT_FG;
|
||||
config.theme.title1 = TFT_FG;
|
||||
config.theme.title2 = TFT_FG;
|
||||
config.theme.rssi = TFT_FG;
|
||||
config.theme.ip = TFT_FG;
|
||||
config.theme.vol = TFT_FG;
|
||||
config.theme.bitrate = TFT_FG;
|
||||
config.theme.digit = TFT_FG;
|
||||
config.theme.buffer = TFT_FG;
|
||||
config.theme.volbarout = TFT_FG;
|
||||
config.theme.volbarin = TFT_FG;
|
||||
|
||||
for(byte i=0;i<5;i++) config.theme.playlist[i] = TFT_FG;
|
||||
|
||||
cp437(true);
|
||||
fillScreen(TFT_BG);
|
||||
flip();
|
||||
invert();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
clearDisplay();
|
||||
drawBitmap(
|
||||
(width() - LOGO_WIDTH ) / 2,
|
||||
8,
|
||||
logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
drawBitmap( (width() - LOGO_WIDTH ) / 2, 8, logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
display();
|
||||
}
|
||||
|
||||
@@ -174,171 +87,103 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 3, PLMITEMS);
|
||||
setTextSize(1);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) + 2, swidth, PLMITEMHEIGHT-1, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 3) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, swidth, PLMITEMHEIGHT - 1, TFT_BG);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, width(), PLMITEMHEIGHT - 1, TFT_BG);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT == 0) return;
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
return CHARWIDTH*clockTimeHeight;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
if(y==90) y=sheight-TFT_LINEHGHT*2-5;
|
||||
if(y==110) y=sheight-TFT_LINEHGHT;
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, y, w, h, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
setTextSize(2);
|
||||
centerText(timestr, 34, TFT_FG, TFT_BG);
|
||||
setTextSize(1);
|
||||
}
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw) {
|
||||
char timeStringBuff[20] = { 0 };
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%H:%M:%S", &timeinfo);
|
||||
setTextSize(2);
|
||||
centerText(timeStringBuff, 30, TFT_FG, TFT_BG);
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - 4;
|
||||
int16_t vWidth = swidth;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_BG);
|
||||
drawRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_LOGO);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop + 1, ww, 1, TFT_LOGO);
|
||||
if (withNumber) {
|
||||
setTextSize(2);
|
||||
setTextColor(TFT_FG);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 22, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 22);
|
||||
print(volstr);
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(2);
|
||||
setTextColor(TFT_FG);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 22, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 22);
|
||||
print(numstr);
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(1);
|
||||
centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strlcpy(buf, str, strlen(str)-2);
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - 4;
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(clockTimeHeight);
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setTextSize(1);
|
||||
rightText(buf, vTop, SILVER, TFT_BG);
|
||||
setCursor(_timeleft+_timewidth+1, clockTop);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds);
|
||||
//setFont();
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - 4;
|
||||
setTextSize(1);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(0, vTop);
|
||||
print(str);
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop, _oldtimewidth, clockTimeHeight*CHARHEIGHT, config.theme.background);
|
||||
_timeleft = (width()/2 - _timewidth/2)+clockRightSpace;
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setTextSize(clockTimeHeight);
|
||||
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
//setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop, _timewidth, clockTimeHeight*CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
void DspCore::startWrite(void) { }
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
void DspCore::endWrite(void) { }
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
if (checkdelay(SCROLLTIME, loopdelay) || force) {
|
||||
display();
|
||||
}
|
||||
display();
|
||||
delay(5);
|
||||
}
|
||||
|
||||
boolean DspCore::checkdelay(int m, unsigned long &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
setRotation(config.store.flipscreen?2:0);
|
||||
}
|
||||
@@ -346,4 +191,35 @@ void DspCore::flip(){
|
||||
void DspCore::invert(){
|
||||
invertDisplay(config.store.invertdisplay);
|
||||
}
|
||||
|
||||
void DspCore::sleep(void) { oled_command(SSD1305_DISPLAYOFF); }
|
||||
void DspCore::wake(void) { oled_command(SSD1305_DISPLAYON); }
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_SSD1305::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_SSD1305::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setTextSize(2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,76 +1,42 @@
|
||||
#ifndef displaySSD1305_h
|
||||
#define displaySSD1305_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1305.h>
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define WEATHER_READY 0
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define DSP_OLED true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 8
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define DSP_OLED
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 10
|
||||
#define META_SIZE 1
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + TFT_LINEHGHT
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + 2 * TFT_LINEHGHT
|
||||
#define PLCURRENT_SIZE 1
|
||||
#define TFT_FULLTIME 1
|
||||
typedef GFXcanvas1 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 2
|
||||
#define SCROLLTIME 35
|
||||
#if __has_include("conf/displaySSD1305conf_custom.h")
|
||||
#include "conf/displaySSD1305conf_custom.h"
|
||||
#else
|
||||
#include "conf/displaySSD1305conf.h"
|
||||
#endif
|
||||
|
||||
class DspCore: public Adafruit_SSD1305 {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void flip();
|
||||
void invert();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
unsigned long loopdelay;
|
||||
boolean checkdelay(int m, unsigned long &tstamp);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
/*
|
||||
* TFT COLORS
|
||||
* OLED COLORS
|
||||
*/
|
||||
#define SILVER WHITE
|
||||
#define TFT_BG BLACK
|
||||
#define TFT_FG WHITE
|
||||
#define TFT_LOGO WHITE
|
||||
#define BOOT_PRG_COLOR WHITE
|
||||
#define BOOT_TXT_COLOR WHITE
|
||||
#define PINK WHITE
|
||||
#define SILVER WHITE
|
||||
#define TFT_BG BLACK
|
||||
#define TFT_FG WHITE
|
||||
#define TFT_LOGO WHITE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_SSD1306 || DSP_MODEL==DSP_SSD1306x32
|
||||
|
||||
#include "displaySSD1306.h"
|
||||
#include <Wire.h>
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef SCREEN_ADDRESS
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#endif
|
||||
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
@@ -30,144 +30,53 @@ const unsigned char logo [] PROGMEM=
|
||||
#endif
|
||||
|
||||
#ifndef I2CFREQ_HZ
|
||||
#define I2CFREQ_HZ 4000000UL
|
||||
#define I2CFREQ_HZ 4000000UL
|
||||
#endif
|
||||
|
||||
TwoWire I2CSSD1306 = TwoWire(0);
|
||||
|
||||
DspCore::DspCore(): Adafruit_SSD1306(128, ((DSP_MODEL==DSP_SSD1306)?64:32), &I2CSSD1306, I2C_RST, I2CFREQ_HZ) {
|
||||
DspCore::DspCore(): Adafruit_SSD1306(128, ((DSP_MODEL==DSP_SSD1306)?64:32), &I2CSSD1306, I2C_RST, I2CFREQ_HZ) { }
|
||||
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + ((DSP_MODEL==DSP_SSD1306)?2:1) * TFT_LINEHGHT);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + ((DSP_MODEL==DSP_SSD1306)?3:2) * TFT_LINEHGHT);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT * 2);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
#endif
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
I2CSSD1306.begin(I2C_SDA, I2C_SCL);
|
||||
if (!begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
|
||||
Serial.println(F("SSD1306 allocation failed"));
|
||||
for (;;); // Don't proceed, loop forever
|
||||
}
|
||||
maxcontrast = DSP_MODEL==DSP_SSD1306?0xCF:0x8F;
|
||||
config.theme.background = TFT_BG;
|
||||
config.theme.meta = TFT_FG;
|
||||
config.theme.meta = TFT_BG;
|
||||
config.theme.clock = TFT_FG;
|
||||
config.theme.weather = TFT_FG;
|
||||
config.theme.metabg = TFT_FG;
|
||||
config.theme.metafill = TFT_FG;
|
||||
config.theme.title1 = TFT_FG;
|
||||
config.theme.title2 = TFT_FG;
|
||||
config.theme.rssi = TFT_FG;
|
||||
config.theme.ip = TFT_FG;
|
||||
config.theme.vol = TFT_FG;
|
||||
config.theme.bitrate = TFT_FG;
|
||||
config.theme.digit = TFT_FG;
|
||||
config.theme.buffer = TFT_FG;
|
||||
config.theme.volbarout = TFT_FG;
|
||||
config.theme.volbarin = TFT_FG;
|
||||
|
||||
for(byte i=0;i<5;i++) config.theme.playlist[i] = TFT_FG;
|
||||
cp437(true);
|
||||
fillScreen(TFT_BG);
|
||||
flip();
|
||||
invert();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
fillSpaces = true;
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
clearDisplay();
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
drawBitmap(
|
||||
(width() - LOGO_WIDTH ) / 2,
|
||||
8,
|
||||
logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
drawBitmap((width() - LOGO_WIDTH ) / 2, 8, logo, LOGO_WIDTH, LOGO_HEIGHT, 1);
|
||||
#else
|
||||
setTextSize(2);
|
||||
centerText(utf8Rus("ёRadio", false), 0, TFT_FG, TFT_BG);
|
||||
setTextSize(1);
|
||||
setCursor((width() - 6*CHARWIDTH) / 2, 0);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
print(utf8Rus("ёRadio", false));
|
||||
setTextSize(1);
|
||||
#endif
|
||||
display();
|
||||
@@ -179,187 +88,114 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 2, PLMITEMS);
|
||||
setTextSize((DSP_MODEL==DSP_SSD1306)?2:1);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) + 1, swidth, PLMITEMHEIGHT, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 2) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, swidth, PLMITEMHEIGHT - 1, TFT_BG);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT, width(), PLMITEMHEIGHT - 1, TFT_BG);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT == 0) return;
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
return CHARWIDTH*clockTimeHeight;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT-((DSP_MODEL==DSP_SSD1306)?0:2), y, w+((DSP_MODEL==DSP_SSD1306)?0:2), h, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
setTextSize(2);
|
||||
centerText(timestr, 34, TFT_FG, TFT_BG);
|
||||
setTextSize(1);
|
||||
#else
|
||||
setTextSize(1);
|
||||
rightText(timestr, 0, TFT_FG, TFT_BG);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw) {
|
||||
#if DSP_MODEL==DSP_SSD1306x32
|
||||
strftime(insideClc, sizeof(insideClc), dots?" %H %M":" %H:%M", &timeinfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - 4;
|
||||
(void)vTop;
|
||||
int16_t vWidth = swidth-TFT_FRAMEWDT*2;
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_BG);
|
||||
drawRect(TFT_FRAMEWDT, vTop, vWidth, 3, TFT_LOGO);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop + 1, ww, 1, TFT_LOGO);
|
||||
#else
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth);
|
||||
if(fillSpaces) {
|
||||
drawFastHLine(TFT_FRAMEWDT, sheight-1, swidth-TFT_FRAMEWDT*2, TFT_BG);
|
||||
drawFastHLine(TFT_FRAMEWDT, sheight-1, ww, TFT_LOGO);
|
||||
}
|
||||
#endif
|
||||
if (withNumber) {
|
||||
setTextSize(2);
|
||||
setTextColor(TFT_FG);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, VOL_TOP, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, VOL_TOP);
|
||||
print(volstr);
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(2);
|
||||
setTextColor(TFT_FG);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, VOL_TOP, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, VOL_TOP);
|
||||
print(numstr);
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize((DSP_MODEL==DSP_SSD1306?2:1));
|
||||
centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
if(!fillSpaces && DSP_MODEL==DSP_SSD1306x32) return;
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strlcpy(buf, str, strlen(str)-2);
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - ((DSP_MODEL==DSP_SSD1306)?4:2);
|
||||
setTextSize(1);
|
||||
rightText(buf, vTop, SILVER, TFT_BG);
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
if(!fillSpaces && DSP_MODEL==DSP_SSD1306x32) return;
|
||||
int16_t vTop = sheight - TFT_LINEHGHT - ((DSP_MODEL==DSP_SSD1306)?4:2);
|
||||
setTextSize(1);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(0, vTop);
|
||||
print(str);
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(clockTimeHeight);
|
||||
#if DSP_MODEL!=DSP_SSD1306x32
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
#else
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? 0 : 1, 1);
|
||||
#endif
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
#if DSP_MODEL!=DSP_SSD1306x32
|
||||
setTextSize(1);
|
||||
setCursor(_timeleft+_timewidth+1, clockTop);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds);
|
||||
#endif
|
||||
//setFont();
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop, _oldtimewidth, clockTimeHeight*CHARHEIGHT, config.theme.background);
|
||||
#if DSP_MODEL!=DSP_SSD1306x32
|
||||
_timeleft = (width()/2 - _timewidth/2)+clockRightSpace;
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
#else
|
||||
_timeleft = (width() - _timewidth)-clockRightSpace;
|
||||
setTextColor(0, 1);
|
||||
#endif
|
||||
setTextSize(clockTimeHeight);
|
||||
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
//setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop, _timewidth, clockTimeHeight*CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
void DspCore::startWrite(void) { }
|
||||
|
||||
void DspCore::endWrite(void) { }
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
if (checkdelay(SCROLLTIME, loopdelay) || force) {
|
||||
#if DSP_MODEL==DSP_SSD1306x32
|
||||
if(fillSpaces) printClock(insideClc);
|
||||
#endif
|
||||
display();
|
||||
}
|
||||
yield();
|
||||
display();
|
||||
delay(5);
|
||||
}
|
||||
|
||||
boolean DspCore::checkdelay(int m, unsigned long &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
setRotation(config.store.flipscreen?2:0);
|
||||
}
|
||||
@@ -371,4 +207,31 @@ void DspCore::invert(){
|
||||
void DspCore::sleep(void) { ssd1306_command(SSD1306_DISPLAYOFF); }
|
||||
void DspCore::wake(void) { ssd1306_command(SSD1306_DISPLAYON); }
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_SSD1306::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_SSD1306::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setTextSize(2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,98 +1,47 @@
|
||||
#ifndef displaySSD1306_h
|
||||
#define displaySSD1306_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define TFT_LINEHGHT 8
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define PLMITEMLENGHT 40
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define DSP_OLED true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 2
|
||||
#define SCROLLTIME 35
|
||||
#endif
|
||||
#define DSP_OLED
|
||||
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
|
||||
#define PLMITEMS 5
|
||||
#define PLMITEMHEIGHT 18
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + 3 * TFT_LINEHGHT
|
||||
#define PLCURRENT_SIZE 2
|
||||
#define BOOTSTR_TOP1 64-TFT_LINEHGHT*2-5
|
||||
#define BOOTSTR_TOP2 64-TFT_LINEHGHT
|
||||
#define VOL_TOP 24
|
||||
typedef GFXcanvas1 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if __has_include("conf/displaySSD1306conf_custom.h")
|
||||
#include "conf/displaySSD1306conf_custom.h"
|
||||
#else
|
||||
|
||||
#define PLMITEMS 5
|
||||
#define PLMITEMHEIGHT 10
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + 2 * TFT_LINEHGHT
|
||||
#define PLCURRENT_SIZE 1
|
||||
#define META_SIZE 1
|
||||
#define TITLE_SIZE2 0
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + META_SIZE * TFT_LINEHGHT + 3
|
||||
#define TFT_FULLTIME 1
|
||||
#define BOOTSTR_TOP1 14
|
||||
#define BOOTSTR_TOP2 24
|
||||
#define CLOCK_SPACE 38
|
||||
#define VOL_SPACE 0
|
||||
#define VOL_TOP 16
|
||||
|
||||
#if DSP_MODEL==DSP_SSD1306
|
||||
#include "conf/displaySSD1306conf.h"
|
||||
#else
|
||||
#include "conf/displaySSD1306x32conf.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
class DspCore: public Adafruit_SSD1306 {
|
||||
public:
|
||||
bool fillSpaces;
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
unsigned long loopdelay;
|
||||
uint8_t maxcontrast;
|
||||
char insideClc[10];
|
||||
boolean checkdelay(int m, unsigned long &tstamp);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
/*
|
||||
* TFT COLORS
|
||||
* OLED COLORS
|
||||
*/
|
||||
#define SILVER WHITE
|
||||
#define TFT_BG BLACK
|
||||
#define TFT_FG WHITE
|
||||
#define TFT_LOGO WHITE
|
||||
#define BOOT_PRG_COLOR WHITE
|
||||
#define BOOT_TXT_COLOR WHITE
|
||||
#define PINK WHITE
|
||||
#define SILVER WHITE
|
||||
#define TFT_BG BLACK
|
||||
#define TFT_FG WHITE
|
||||
#define TFT_LOGO WHITE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,155 +1,65 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_SSD1327
|
||||
|
||||
#include "displaySSD1327.h"
|
||||
#include <Wire.h>
|
||||
#include "fonts/bootlogobw.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "fonts/bootlogo40.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef SCREEN_ADDRESS
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; or scan it https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef I2CFREQ_HZ
|
||||
#define I2CFREQ_HZ 6000000UL
|
||||
#define I2CFREQ_HZ 6000000UL
|
||||
#endif
|
||||
|
||||
TwoWire tw = TwoWire(0);
|
||||
|
||||
DspCore::DspCore(): Adafruit_SSD1327(128, 128, &tw, I2C_RST, I2CFREQ_HZ) {
|
||||
DspCore::DspCore(): Adafruit_SSD1327(128, 128, &tw, I2C_RST/*, I2CFREQ_HZ*/) {}
|
||||
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + ((DSP_MODEL==DSP_SSD1306)?2:1) * TFT_LINEHGHT);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + ((DSP_MODEL==DSP_SSD1306)?3:2) * TFT_LINEHGHT);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT * 2);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight - TFT_LINEHGHT);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
}
|
||||
#define CLR_ITEM1 0xA
|
||||
#define CLR_ITEM2 0x8
|
||||
#define CLR_ITEM3 0x5
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
tw.begin(I2C_SDA, I2C_SCL);
|
||||
if (!begin(SCREEN_ADDRESS)) {
|
||||
Serial.println(F("SSD1327 allocation failed"));
|
||||
for (;;);
|
||||
}
|
||||
config.theme.background = TFT_BG;
|
||||
config.theme.meta = TFT_FG;
|
||||
config.theme.title1 = TFT_FG;
|
||||
config.theme.meta = TFT_BG;
|
||||
config.theme.metabg = TFT_LOGO;
|
||||
config.theme.metafill = TFT_LOGO;
|
||||
config.theme.title1 = TFT_LOGO;
|
||||
config.theme.title2 = SILVER;
|
||||
config.theme.clock = TFT_LOGO;
|
||||
config.theme.rssi = TFT_FG;
|
||||
config.theme.weather = ORANGE;
|
||||
config.theme.heap = SILVER;
|
||||
config.theme.ip = SILVER;
|
||||
config.theme.vol = SILVER;
|
||||
config.theme.bitrate = TFT_LOGO;
|
||||
config.theme.digit = TFT_LOGO;
|
||||
config.theme.buffer = TFT_FG;
|
||||
config.theme.volbarout = TFT_FG;
|
||||
config.theme.volbarin = SILVER;
|
||||
config.theme.playlist[0] = CLR_ITEM1;
|
||||
config.theme.playlist[1] = CLR_ITEM2;
|
||||
config.theme.playlist[2] = CLR_ITEM3;
|
||||
config.theme.playlist[3] = CLR_ITEM3;
|
||||
config.theme.playlist[4] = CLR_ITEM3;
|
||||
cp437(true);
|
||||
fillScreen(TFT_BG);
|
||||
flip();
|
||||
invert();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
setClockBounds();
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
drawGrayscaleBitmap((swidth - 99) / 2, 18, bootlogobw, 99, 64);
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
drawRGBBitmap((DSP_WIDTH - 62) / 2, top, bootlogo40, 62, 40);
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
@@ -158,8 +68,7 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 3, PLMITEMS);
|
||||
setTextSize(2);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) - 1, swidth, PLMITEMHEIGHT + 2, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (abs(i - 3) == 3) setTextColor(CLR_ITEM3, TFT_BG);
|
||||
if (abs(i - 3) == 2) setTextColor(CLR_ITEM2, TFT_BG);
|
||||
@@ -168,252 +77,97 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, swidth, PLMITEMHEIGHT - 4, TFT_BG);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, width(), PLMITEMHEIGHT - 4, TFT_BG);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
//display();
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
fillScreen(TFT_BG);
|
||||
//clearDisplay();
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(black?0:config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT == 0) return;
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI28pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, swidth, textheight, bg);
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(txt);
|
||||
//display();
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg, bg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, y, w, h, bg);
|
||||
print(text);
|
||||
//display();
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT * 2 - 2;
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(1);
|
||||
setTextColor(DARK_GRAY, TFT_BG);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, TFT_BG);
|
||||
print(ESP.getFreeHeap());
|
||||
print(" / ");
|
||||
print(ESP.getMaxAllocHeap());
|
||||
// audio buffer;
|
||||
fillRect(0, sheight - 2, swidth, 2, TFT_BG);
|
||||
int astored = player.inBufferFilled();
|
||||
int afree = player.inBufferFree();
|
||||
int aprcnt = 100 * astored / (astored + afree);
|
||||
byte sbw = map(aprcnt, 0, 100 , 0, swidth);
|
||||
fillRect(0, sheight - 2, sbw, 2, DARK_GRAY);
|
||||
}
|
||||
|
||||
void DspCore::setClockBounds(){
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
getTextBounds("88:88", 0, 0, &x, &y, &cwidth, &cheight);
|
||||
uint16_t header = TFT_FRAMEWDT + 4 * TFT_LINEHGHT;
|
||||
uint16_t footer = TFT_FRAMEWDT * 2 + TFT_LINEHGHT + 5;
|
||||
clockY = header + (sheight - header - footer) / 2 - cheight / 2;
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
/* uint16_t ncwidth, ncheight;
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = (width()/2 - _timewidth/2)+clockRightSpace;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot);
|
||||
setCursor((swidth - wot) / 2 - 4, clockY+28+6);
|
||||
setTextColor(TFT_BG);
|
||||
print(oldTimeBuf);
|
||||
strlcpy(oldTimeBuf, timestr, 20);
|
||||
setTextColor(TFT_LOGO);
|
||||
//fillRect(0, clockY, swidth, cheight + 3, TFT_BG);
|
||||
getTextBounds(timestr, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
setCursor((swidth - ncwidth) / 2 - 4, clockY+28+6);
|
||||
print(timestr);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
//display();*/
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
byte DspCore::getPw(uint16_t ncwidth){
|
||||
byte pw = 6;
|
||||
if(ncwidth<35) pw = 7;
|
||||
if(ncwidth<20) pw = 8;
|
||||
return pw;
|
||||
}
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
|
||||
char timeBuf[50] = { 0 };
|
||||
char tmpBuf[4] = { 0 };
|
||||
uint16_t ncwidth, ncheight;
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H %M", &timeinfo);
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot);
|
||||
setCursor((swidth - wot) / 2 - 4, clockY+28+6);
|
||||
setTextColor(TFT_BG);
|
||||
print(oldTimeBuf);
|
||||
dot = (swidth - wot) / 2 - 4;
|
||||
/* dots */
|
||||
strlcpy(tmpBuf, oldTimeBuf, 3);
|
||||
getTextBounds(tmpBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
dot = dot + ncwidth + getPw(ncwidth);
|
||||
setCursor(dot, clockY+28+6);
|
||||
print(":");
|
||||
/* dots */
|
||||
|
||||
strlcpy(oldTimeBuf, timeBuf, 20);
|
||||
setTextSize(1);
|
||||
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
setTextColor(TFT_LOGO);
|
||||
setCursor((swidth - ncwidth) / 2 - 4, clockY+28+6);
|
||||
dot = (swidth - ncwidth) / 2 - 4;
|
||||
setTextSize(1);
|
||||
print(timeBuf);
|
||||
/* dots */
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H", &timeinfo);
|
||||
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
dot = dot + ncwidth + getPw(ncwidth);
|
||||
/* dots */
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
setCursor(dot, clockY+28+6);
|
||||
setTextColor(dots?TFT_BG:TFT_LOGO);
|
||||
print(":");
|
||||
setFont();
|
||||
display();
|
||||
//_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
//if (withNumber) delay(150); /* buuuut iiiiit's toooooo faaaast 0000__oooo !!111 ommm____nomm____nomm */
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT - 4;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, TFT_BG);
|
||||
drawRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, TFT_LOGO);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop - 1, ww, 5, TFT_LOGO);
|
||||
if (withNumber) {
|
||||
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 48, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
//fillRect(24, 48, 80, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 48 + hv);
|
||||
print(volstr);
|
||||
setFont();
|
||||
}
|
||||
//display();
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth, clockTimeHeight, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(1);
|
||||
setTextColor(TFT_FG);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, 48, swidth - TFT_FRAMEWDT / 2, hv + 3, TFT_BG);
|
||||
setCursor((swidth - wv) / 2, 48 + hv);
|
||||
print(numstr);
|
||||
setFont();
|
||||
//display();
|
||||
}
|
||||
void DspCore::startWrite(void) { }
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(2);
|
||||
centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG);
|
||||
//display();
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
setTextSize(1);
|
||||
rightText(str, vTop, SILVER, TFT_BG);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
setTextSize(1);
|
||||
setTextColor(SILVER, TFT_BG);
|
||||
setCursor(4, vTop);
|
||||
print(str);
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
//display();
|
||||
}
|
||||
void DspCore::endWrite(void) { }
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
if (checkdelay(LOOP_DELAY, loopdelay) || force) {
|
||||
display();
|
||||
}
|
||||
yield();
|
||||
display();
|
||||
delay(5);
|
||||
}
|
||||
|
||||
boolean DspCore::checkdelay(int m, unsigned long &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
if(ROTATE_90){
|
||||
setRotation(config.store.flipscreen?3:1);
|
||||
@@ -429,4 +183,32 @@ void DspCore::invert(){
|
||||
void DspCore::sleep(void) { oled_command(SSD1327_DISPLAYOFF); }
|
||||
void DspCore::wake(void) { oled_command(SSD1327_DISPLAYON); }
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_SSD1327::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_SSD1327::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,75 +1,30 @@
|
||||
#ifndef displaySSD1327_h
|
||||
#define displaySSD1327_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1327.h>
|
||||
#include "fonts/DS_DIGI28pt7b.h"
|
||||
#include "fonts/DS_DIGI28pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define WEATHER_READY 1
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#define TFT_FRAMEWDT 4
|
||||
#define DSP_OLED
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + 3 * TFT_LINEHGHT
|
||||
typedef GFXcanvas1 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
|
||||
#define SCROLLDELTA 2
|
||||
#define SCROLLTIME 30
|
||||
#define LOOP_DELAY 33
|
||||
#if __has_include("conf/displaySSD1327conf_custom.h")
|
||||
#include "conf/displaySSD1327conf_custom.h"
|
||||
#else
|
||||
#include "conf/displaySSD1327conf.h"
|
||||
#endif
|
||||
|
||||
#define TFT_FULLTIME 1
|
||||
|
||||
class DspCore: public Adafruit_SSD1327 {
|
||||
public:
|
||||
bool fillSpaces;
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
int16_t x, y;
|
||||
uint16_t cwidth, cheight;
|
||||
unsigned long loopdelay;
|
||||
char oldTimeBuf[20];
|
||||
uint16_t wot, hot, dot;
|
||||
boolean checkdelay(int m, unsigned long &tstamp);
|
||||
void setClockBounds();
|
||||
byte getPw(uint16_t ncwidth);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
@@ -83,12 +38,14 @@ extern DspCore dsp;
|
||||
/*
|
||||
* TFT COLORS
|
||||
*/
|
||||
#define BOOT_PRG_COLOR 0x07
|
||||
#define BOOT_TXT_COLOR 0x3f
|
||||
#define DARK_GRAY 0x01
|
||||
#define SILVER 0x07
|
||||
#define TFT_BG 0x00
|
||||
#define TFT_FG 0x08
|
||||
#define TFT_LOGO 0x3f
|
||||
#define ORANGE 0x02
|
||||
#define ORANGE 0x05
|
||||
#define PINK 0x02
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ST7735
|
||||
|
||||
#include "displayST7735.h"
|
||||
#include <SPI.h>
|
||||
#ifdef DSP_MINI
|
||||
#include "fonts/bootlogo40.h"
|
||||
#else
|
||||
#include "fonts/bootlogo.h"
|
||||
#endif
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef DEF_SPI_FREQ
|
||||
#define DEF_SPI_FREQ 26000000UL /* set it to 0 for system default */
|
||||
#endif
|
||||
|
||||
#if DTYPE==INITR_BLACKTAB
|
||||
#define CLOCK_DELTA 12
|
||||
#elif DTYPE==INITR_MINI160x80
|
||||
#define CLOCK_DELTA 16
|
||||
#else
|
||||
#define CLOCK_DELTA 0
|
||||
#endif
|
||||
|
||||
#define TAKE_MUTEX() if(player.mutex_pl) xSemaphoreTake(player.mutex_pl, portMAX_DELAY)
|
||||
#define GIVE_MUTEX() if(player.mutex_pl) xSemaphoreGive(player.mutex_pl)
|
||||
|
||||
@@ -31,119 +18,23 @@ DspCore::DspCore(): Adafruit_ST7735(&SPI, TFT_CS, TFT_DC, TFT_RST) {
|
||||
|
||||
}
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.title1, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 2 * TFT_LINEHGHT);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TFT_FRAMEWDT + 3 * TFT_LINEHGHT);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(config.theme.title2, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, 107);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, 117);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
initR(DTYPE);
|
||||
if(DEF_SPI_FREQ > 0) setSPISpeed(DEF_SPI_FREQ);
|
||||
cp437(true);
|
||||
invert();
|
||||
// fillScreen(0x0000);
|
||||
flip();
|
||||
setTextWrap(false);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
setClockBounds();
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
fillScreen(0x0000);
|
||||
void DspCore::drawLogo(uint16_t top) {
|
||||
#ifdef DSP_MINI
|
||||
drawRGBBitmap((swidth - 62) / 2, 5, bootlogo40, 62, 40);
|
||||
drawRGBBitmap((DSP_WIDTH - 62) / 2, 5, bootlogo40, 62, 40);
|
||||
#else
|
||||
drawRGBBitmap((swidth - 99) / 2, 18, bootlogo2, 99, 64);
|
||||
//drawRGBBitmap((DSP_WIDTH - 99) / 2, 18, bootlogo2, 99, 64);
|
||||
drawRGBBitmap((DSP_WIDTH - 62) / 2, 34, bootlogo40, 62, 40);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -153,8 +44,7 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 3, PLMITEMS);
|
||||
setTextSize(2);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
//fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) - 1, swidth, PLMITEMHEIGHT + 2, TFT_LOGO);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (abs(i - 3) == 3) setTextColor(config.theme.playlist[2], config.theme.background);
|
||||
if (abs(i - 3) == 2) setTextColor(config.theme.playlist[1], config.theme.background);
|
||||
@@ -163,209 +53,77 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, swidth, PLMITEMHEIGHT - 4, config.theme.background);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, DSP_WIDTH, PLMITEMHEIGHT - 4, config.theme.background);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
fillScreen(config.theme.background);
|
||||
void DspCore::clearDsp(bool black) {
|
||||
fillScreen(black?0:config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI28pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop-2, swidth, textheight+3, bg);
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect(0, y, swidth, h, bg);
|
||||
print(txt);
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, y, w, h, bg);
|
||||
print(text);
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
#ifndef DSP_MINI
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT * 2 - 2;
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.heap, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, config.theme.background);
|
||||
print(ESP.getFreeHeap());
|
||||
print(" / ");
|
||||
print(ESP.getMaxAllocHeap());
|
||||
// audio buffer;
|
||||
fillRect(0, sheight - 2, swidth, 2, config.theme.background);
|
||||
int astored = player.inBufferFilled();
|
||||
int afree = player.inBufferFree();
|
||||
int aprcnt = 100 * astored / (astored + afree);
|
||||
byte sbw = map(aprcnt, 0, 100 , 0, swidth);
|
||||
fillRect(0, sheight - 2, sbw, 2, config.theme.title2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DspCore::setClockBounds(){
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
getTextBounds("88:88", 0, 0, &x, &y, &cwidth, &cheight);
|
||||
uint16_t header = TFT_FRAMEWDT + 4 * TFT_LINEHGHT;
|
||||
uint16_t footer = TFT_FRAMEWDT * 2 + TFT_LINEHGHT + 5;
|
||||
clockY = header + (sheight - header - footer) / 2 - cheight / 2;
|
||||
if(DTYPE==INITR_MINI160x80) clockY = clockY-6;
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
void DspCore::_clockDate(){ }
|
||||
|
||||
}
|
||||
|
||||
byte DspCore::getPw(uint16_t ncwidth){
|
||||
byte pw = 6;
|
||||
if(ncwidth<35) pw = 7;
|
||||
if(ncwidth<20) pw = 8;
|
||||
return pw;
|
||||
}
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
|
||||
char timeBuf[50] = { 0 };
|
||||
char tmpBuf[4] = { 0 };
|
||||
uint16_t ncwidth, ncheight;
|
||||
uint16_t clockdelta=config.store.vumeter?CLOCK_DELTA:0;
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H %M", &timeinfo);
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = (width()/2 - _timewidth/2)+clockRightSpace;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x, &y, &wot, &hot);
|
||||
setCursor((swidth - wot) / 2 - 4 + clockdelta, clockY+28+6);
|
||||
setTextColor(config.theme.background);
|
||||
print(oldTimeBuf);
|
||||
dot = (swidth - wot) / 2 - 4 + clockdelta;
|
||||
/* dots */
|
||||
strlcpy(tmpBuf, oldTimeBuf, 3);
|
||||
getTextBounds(tmpBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
dot = dot + ncwidth + getPw(ncwidth);
|
||||
setCursor(dot, clockY+28+6);
|
||||
print(":");
|
||||
/* dots */
|
||||
|
||||
strlcpy(oldTimeBuf, timeBuf, 20);
|
||||
setTextSize(1);
|
||||
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
setTextColor(config.theme.clock);
|
||||
setCursor((swidth - ncwidth) / 2 - 4 + clockdelta, clockY+28+6);
|
||||
dot = (swidth - ncwidth) / 2 - 4 + clockdelta;
|
||||
setTextSize(1);
|
||||
print(timeBuf);
|
||||
/* dots */
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H", &timeinfo);
|
||||
getTextBounds(timeBuf, 0, 0, &x, &y, &ncwidth, &ncheight);
|
||||
dot = dot + ncwidth + getPw(ncwidth);
|
||||
/* dots */
|
||||
}
|
||||
setCursor(dot, clockY+28+6);
|
||||
setTextColor(dots?config.theme.background:config.theme.clock);
|
||||
print(":");
|
||||
setFont();
|
||||
yield();
|
||||
}
|
||||
#ifdef DSP_MINI
|
||||
#define VTOP TITLE_TOP1+6
|
||||
#else
|
||||
#define VTOP 48
|
||||
#endif
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
#ifdef DSP_MINI
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT - 2;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT * 2;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth);
|
||||
fillRect(TFT_FRAMEWDT, vTop, vWidth, 2, config.theme.background);
|
||||
fillRect(TFT_FRAMEWDT, vTop, ww, 2, config.theme.volbarin);
|
||||
#else
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT - 6;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT * 2;
|
||||
uint8_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop - 2 + 3, vWidth, 5, config.theme.background);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop - 1 + 3, ww, 3, config.theme.volbarin);
|
||||
drawRect(TFT_FRAMEWDT, vTop - 2 + 3, vWidth, 5, config.theme.volbarout);
|
||||
#endif
|
||||
if (withNumber) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, VTOP, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, VTOP + hv);
|
||||
print(volstr);
|
||||
setFont();
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, VTOP, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, VTOP + hv);
|
||||
print(numstr);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(2);
|
||||
centerText(str, TFT_FRAMEWDT, config.theme.meta, config.theme.background);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
setTextSize(1);
|
||||
rightText(str, vTop, config.theme.rssi, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.ip, config.theme.background);
|
||||
setCursor(4, vTop);
|
||||
print(str);
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth, clockTimeHeight, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::startWrite(void) {
|
||||
@@ -378,24 +136,15 @@ void DspCore::endWrite(void) {
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
void DspCore::loop(bool force) { }
|
||||
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
@@ -417,4 +166,32 @@ void DspCore::wake(void) {
|
||||
enableDisplay(true); delay(150); enableSleep(false); delay(150);
|
||||
}
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_ST7735::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_ST7735::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI28pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,89 +1,39 @@
|
||||
#ifndef displayST7735_h
|
||||
#define displayST7735_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_ST7735.h>
|
||||
#include "fonts/DS_DIGI28pt7b.h"
|
||||
#include "fonts/DS_DIGI28pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define VU_READY 1
|
||||
#define WEATHER_READY 1
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#if DTYPE==INITR_MINI160x80
|
||||
#define TFT_FRAMEWDT 0
|
||||
#define DSP_MINI
|
||||
typedef GFXcanvas16 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
|
||||
#if __has_include("conf/displayST7735conf_custom.h")
|
||||
#include "conf/displayST7735conf_custom.h"
|
||||
#else
|
||||
#define TFT_FRAMEWDT 4
|
||||
#if DTYPE==INITR_MINI160x80
|
||||
#include "conf/displayST7735_miniconf.h"
|
||||
#elif DTYPE==INITR_144GREENTAB
|
||||
#include "conf/displayST7735_144conf.h"
|
||||
#else
|
||||
#include "conf/displayST7735_blackconf.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define PLMITEMS 7
|
||||
#define PLMITEMLENGHT 40
|
||||
#if DTYPE==INITR_MINI160x80
|
||||
#define PLMITEMHEIGHT 19
|
||||
#else
|
||||
#define PLMITEMHEIGHT 21
|
||||
#endif
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + 3 * TFT_LINEHGHT
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 2
|
||||
#define SCROLLTIME 30
|
||||
#endif
|
||||
|
||||
#define TFT_FULLTIME 1
|
||||
|
||||
#if DTYPE==INITR_MINI160x80
|
||||
#define TITLE_SIZE2 0
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + 2 * TFT_LINEHGHT-3
|
||||
#define BOOTSTR_TOP1 50
|
||||
#define BOOTSTR_TOP2 65
|
||||
#endif
|
||||
#define BOOT_PRG_COLOR 0xE68B
|
||||
#define BOOT_TXT_COLOR 0xFFFF
|
||||
#define PINK 0xF97F
|
||||
|
||||
class DspCore: public Adafruit_ST7735 {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
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 set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
virtual void startWrite(void);
|
||||
virtual void endWrite(void);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
char oldTimeBuf[20];
|
||||
uint16_t wot, hot, dot;
|
||||
int16_t x, y;
|
||||
uint16_t cwidth, cheight;
|
||||
void setClockBounds();
|
||||
byte getPw(uint16_t ncwidth);
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
@@ -1,138 +1,36 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ST7789 || DSP_MODEL==DSP_ST7789_240
|
||||
|
||||
#include "displayST7789.h"
|
||||
#include <SPI.h>
|
||||
//#include <SPI.h>
|
||||
#include "fonts/bootlogo.h"
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef DEF_SPI_FREQ
|
||||
#define DEF_SPI_FREQ 40000000UL /* set it to 0 for system default */
|
||||
#define DEF_SPI_FREQ 40000000UL /* set it to 0 for system default */
|
||||
#endif
|
||||
const char *dow[7] = {"вс","пн","вт","ср","чт","пт","сб"};
|
||||
const char *mnths[12] = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"};
|
||||
|
||||
#define TAKE_MUTEX() if(player.mutex_pl) xSemaphoreTake(player.mutex_pl, portMAX_DELAY)
|
||||
#define GIVE_MUTEX() if(player.mutex_pl) xSemaphoreGive(player.mutex_pl)
|
||||
|
||||
DspCore::DspCore(): Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST) {
|
||||
DspCore::DspCore(): Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST) {}
|
||||
|
||||
}
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
if (uppercase) {
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
}
|
||||
while (strn[index])
|
||||
{
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
if (strn[index + 1] == 0x81) {
|
||||
strn[index] = 0xA8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x90 && strn[index + 1] <= 0xBF) strn[index] = strn[index + 1] + 0x30;
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
//strn[index] = 0xB7;
|
||||
strn[index] = 0xB8;
|
||||
break;
|
||||
}
|
||||
if (strn[index + 1] >= 0x80 && strn[index + 1] <= 0x8F) strn[index] = strn[index + 1] + 0x70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
setTextSize(TITLE_SIZE1);
|
||||
setTextColor(config.theme.title1, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, TITLE_TOP1);
|
||||
print("AP NAME: ");
|
||||
print(apSsid);
|
||||
setCursor(TFT_FRAMEWDT, TITLE_TOP2);
|
||||
print("PASSWORD: ");
|
||||
print(apPassword);
|
||||
setTextColor(config.theme.title2, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, sheight-TFT_FRAMEWDT-TFT_LINEHGHT*4);
|
||||
print("SETTINGS PAGE ON: ");
|
||||
setCursor(TFT_FRAMEWDT, sheight-TFT_FRAMEWDT-TFT_LINEHGHT*2);
|
||||
print("http://");
|
||||
print(WiFi.softAPIP().toString().c_str());
|
||||
print("/");
|
||||
drawFastHLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, config.theme.div);
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
void DspCore::initDisplay() {
|
||||
init(240,(DSP_MODEL==DSP_ST7789)?320:240);
|
||||
if(DEF_SPI_FREQ > 0) setSPISpeed(DEF_SPI_FREQ);
|
||||
invert();
|
||||
cp437(true);
|
||||
// fillScreen(0x0000);
|
||||
flip();
|
||||
setTextWrap(false);
|
||||
setTextSize(1);
|
||||
screenwidth = width();
|
||||
screenheight = height();
|
||||
swidth = screenwidth;
|
||||
sheight = screenheight;
|
||||
fillScreen(0x0000);
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
fillScreen(0x0000);
|
||||
drawRGBBitmap((swidth - 99) / 2, (sheight-64)/2 - TFT_LINEHGHT*2, bootlogo2, 99, 64);
|
||||
}
|
||||
void DspCore::drawLogo(uint16_t top) { drawRGBBitmap((width() - 99) / 2, top, bootlogo2, 99, 64); }
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
@@ -140,216 +38,108 @@ void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 5, PLMITEMS);
|
||||
setTextSize(2);
|
||||
int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 5) {
|
||||
//fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) - 1, swidth, PLMITEMHEIGHT + 2, TFT_LOGO);
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setTextColor(config.theme.playlist[abs(i - 5)-1], config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, swidth, PLMITEMHEIGHT - 2, config.theme.background);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, width(), PLMITEMHEIGHT - 2, config.theme.background);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
fillScreen(config.theme.background);
|
||||
void DspCore::clearDsp(bool black) { fillScreen(black?0:config.theme.background); }
|
||||
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
if (TFT_FRAMEWDT==0) return;
|
||||
fillRect(swidth - TFT_FRAMEWDT, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
fillRect(0, texttop, TFT_FRAMEWDT, textheight, bg);
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI42pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
setTextSize(textsize);
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
tWidth = w;
|
||||
tHeight = h;
|
||||
getTextBounds(separator, 0, 0, &x1, &y1, &w, &h);
|
||||
sWidth = w;
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
fillRect(0, texttop-4, swidth, textheight+7, bg);
|
||||
yield();
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, uint16_t y, uint16_t fg, uint16_t bg) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
const char* txt = text;
|
||||
if(y==90) y=(sheight-64)/2 + 64 + TFT_LINEHGHT;
|
||||
if(y==110) y=(sheight-64)/2 + 64 + TFT_LINEHGHT*3;
|
||||
getTextBounds(txt, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg);
|
||||
setCursor((swidth - w) / 2, y);
|
||||
fillRect((swidth-w)/2-5, y, w+10, h, bg);
|
||||
print(txt);
|
||||
yield();
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, uint16_t y, uint16_t fg, uint16_t bg, bool fliprect, uint16_t delta) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
setTextColor(fg,bg);
|
||||
setCursor(swidth - w - TFT_FRAMEWDT - delta, y);
|
||||
fillRect(swidth - w - TFT_FRAMEWDT, fliprect?y-h:y, w, h, bg);
|
||||
print(text);
|
||||
yield();
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT * 2 - 2;
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.heap, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
fillRect(TFT_FRAMEWDT, vTop, swidth - TFT_FRAMEWDT / 2, 7, config.theme.background);
|
||||
print(ESP.getFreeHeap());
|
||||
print(" / ");
|
||||
print(ESP.getMaxAllocHeap());
|
||||
// audio buffer;
|
||||
fillRect(0, sheight - 2, swidth, 2, config.theme.background);
|
||||
int astored = player.inBufferFilled();
|
||||
int afree = player.inBufferFree();
|
||||
int aprcnt = 100 * astored / (astored + afree);
|
||||
uint16_t sbw = map(aprcnt, 0, 100 , 0, swidth);
|
||||
fillRect(0, sheight - 2, sbw, 2, config.theme.buffer);
|
||||
yield();
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
|
||||
}
|
||||
|
||||
uint16_t cltop = 0;
|
||||
uint8_t clsp = 24;
|
||||
uint16_t clleft = 0;
|
||||
uint16_t clwidth = 0;
|
||||
|
||||
void DspCore::printClock(struct tm timeinfo, bool dots, bool redraw){
|
||||
char timeBuf[50] = { 0 };
|
||||
strftime(timeBuf, sizeof(timeBuf), "%H:%M", &timeinfo);
|
||||
if(strstr(oldTimeBuf, timeBuf)==NULL || redraw){
|
||||
int16_t x1, y1;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
getTextBounds(oldTimeBuf, 0, 0, &x1, &y1, &wot, &hot);
|
||||
if(cltop==0){
|
||||
cltop=sheight-(TFT_FRAMEWDT * 2 + TFT_LINEHGHT + 38) - hot;
|
||||
}
|
||||
clwidth = wot+clsp+(swidth>240?46:34);
|
||||
fillRect(swidth-TFT_FRAMEWDT-clwidth, cltop-hot, clwidth, hot+3, config.theme.background);
|
||||
strlcpy(oldTimeBuf, timeBuf, 20);
|
||||
setTextSize(1);
|
||||
getTextBounds(timeBuf, 0, 0, &x1, &y1, &wot, &hot);
|
||||
clwidth = wot+clsp+(swidth>240?46:34);
|
||||
clleft=swidth-TFT_FRAMEWDT-clwidth;
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(clleft, cltop);
|
||||
setTextSize(1);
|
||||
print(timeBuf);
|
||||
|
||||
setFont();
|
||||
setTextSize(3);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(clleft+wot+clsp, cltop-hot+32);
|
||||
print(utf8Rus(dow[timeinfo.tm_wday], false));
|
||||
|
||||
sprintf(timeBuf, "%2d %s %d", timeinfo.tm_mday,mnths[timeinfo.tm_mon], timeinfo.tm_year+1900);
|
||||
setTextSize(1);
|
||||
uint16_t wdate, hdate;
|
||||
getTextBounds(timeBuf, 0, 0, &x1, &y1, &wdate, &hdate);
|
||||
fillRect(swidth - wdate - TFT_FRAMEWDT-20, cltop+10, wdate+20, hdate, config.theme.background);
|
||||
rightText(utf8Rus(timeBuf,true), cltop+10, config.theme.date, config.theme.background, false, swidth>240?12:0);
|
||||
drawFastVLine(clleft+wot+clsp/2+3, cltop-hot, hot+3, config.theme.div);
|
||||
drawFastHLine(clleft+wot+clsp/2+3, cltop-hot+29, 42, config.theme.div);
|
||||
|
||||
drawFastHLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, config.theme.div);
|
||||
}
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(3);
|
||||
setTextColor(config.theme.seconds, config.theme.background);
|
||||
setCursor(clleft+wot+clsp, cltop-hot+1);
|
||||
sprintf(timeBuf, "%02d", timeinfo.tm_sec);
|
||||
print(timeBuf);
|
||||
yield();
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2;
|
||||
int16_t volTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
int16_t vWidth = swidth - TFT_FRAMEWDT *2;
|
||||
uint16_t ww = map(config.store.volume, 0, 254, 0, vWidth - 2);
|
||||
fillRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, config.theme.background);
|
||||
fillRect(TFT_FRAMEWDT + 1, vTop - 1, ww, 5, config.theme.volbarin);
|
||||
drawRect(TFT_FRAMEWDT, vTop - 2, vWidth, 6, config.theme.volbarout);
|
||||
if(swidth>240){
|
||||
char buf[20];
|
||||
sprintf(buf, "VOL %d", config.store.volume);
|
||||
setTextSize(1);
|
||||
centerText(buf, volTop, config.theme.vol, config.theme.background);
|
||||
}
|
||||
if (withNumber) {
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
char volstr[4];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(volstr, "%d", config.store.volume);
|
||||
getTextBounds(volstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, (sheight-hv)/2, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(volstr);
|
||||
setFont();
|
||||
}
|
||||
yield();
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*3*2, clockTop-clockTimeHeight+1);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds); /* print seconds */
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.digit);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
char numstr[7];
|
||||
uint16_t wv, hv;
|
||||
int16_t x1, y1;
|
||||
sprintf(numstr, "%d", num);
|
||||
getTextBounds(numstr, 0, 0, &x1, &y1, &wv, &hv);
|
||||
fillRect(TFT_FRAMEWDT, (sheight-hv)/2, swidth - TFT_FRAMEWDT / 2, hv + 3, config.theme.background);
|
||||
setCursor((swidth - wv) / 2, (sheight-hv)/2 + hv);
|
||||
print(numstr);
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
setTextSize(META_SIZE);
|
||||
centerText(str, TFT_FRAMEWDT, config.theme.meta, config.theme.background);
|
||||
drawFastHLine(TFT_FRAMEWDT, TITLE_TOP1-8, swidth-TFT_FRAMEWDT*2, config.theme.div);
|
||||
void DspCore::_clockDate(){
|
||||
if(_olddateleft>0)
|
||||
dsp.fillRect(_olddateleft, clockTop+10, _olddatewidth, CHARHEIGHT, config.theme.background);
|
||||
setTextColor(config.theme.date, config.theme.background);
|
||||
setCursor(_dateleft, clockTop+10);
|
||||
print(_dateBuf); /* print date */
|
||||
strlcpy(_oldDateBuf, _dateBuf, sizeof(_dateBuf));
|
||||
_olddatewidth = _datewidth;
|
||||
_olddateleft = _dateleft;
|
||||
setTextSize(3);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*3*2, clockTop-CHARHEIGHT*3+4);
|
||||
print(utf8Rus(dow[network.timeinfo.tm_wday], false)); /* print dow */
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
char buf[20];
|
||||
sprintf(buf, "RSSI:%s", str);
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = width()-clockRightSpace-CHARWIDTH*3*2-24-_timewidth;
|
||||
setTextSize(1);
|
||||
rightText(buf, vTop, config.theme.rssi, config.theme.background);
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
drawFastVLine(width()-clockRightSpace-CHARWIDTH*3*2-18, clockTop-clockTimeHeight, clockTimeHeight+3, config.theme.div); /*divider vert*/
|
||||
drawFastHLine(width()-clockRightSpace-CHARWIDTH*3*2-18, clockTop-clockTimeHeight+29, 44, config.theme.div); /*divider hor*/
|
||||
sprintf(_buffordate, "%2d %s %d", network.timeinfo.tm_mday,mnths[network.timeinfo.tm_mon], network.timeinfo.tm_year+1900);
|
||||
strlcpy(_dateBuf, utf8Rus(_buffordate, true), sizeof(_dateBuf));
|
||||
_datewidth = strlen(_dateBuf) * CHARWIDTH;
|
||||
_dateleft = width() - 8 - clockRightSpace - _datewidth;
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
int16_t vTop = sheight - TFT_FRAMEWDT * 2 - TFT_LINEHGHT - 2;
|
||||
char buf[30];
|
||||
sprintf(buf, "IP: %s", str);
|
||||
setTextSize(1);
|
||||
setTextColor(config.theme.ip, config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, vTop);
|
||||
print(buf);
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
if(strcmp(_oldDateBuf, _dateBuf)!=0 || redraw) _clockDate();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*3*2+24, clockTimeHeight+10+CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::startWrite(void) {
|
||||
@@ -362,25 +152,19 @@ void DspCore::endWrite(void) {
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
setTextColor(fg, bg);
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
setCursor(x, y);
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
print(txt);
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
#if DSP_MODEL==DSP_ST7789
|
||||
setRotation(config.store.flipscreen?3:1);
|
||||
@@ -405,4 +189,32 @@ void DspCore::wake(void) {
|
||||
enableDisplay(true); delay(150); enableSleep(false); delay(150);
|
||||
}
|
||||
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_ST7789::writePixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
Adafruit_ST7789::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI42pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,75 +1,36 @@
|
||||
#ifndef displayST7789_h
|
||||
#define displayST7789_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_ST7789.h>
|
||||
// https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "fonts/DS_DIGI42pt7b.h"
|
||||
#include "fonts/DS_DIGI42pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define VU_READY 1
|
||||
#define WEATHER_READY 1
|
||||
#define DSP_CAN_SLEEP true
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
#define TFT_LINEHGHT 10
|
||||
#define TFT_FRAMEWDT 8
|
||||
#define META_SIZE 3
|
||||
#define TITLE_SIZE1 2
|
||||
#define TITLE_SIZE2 2
|
||||
typedef GFXcanvas16 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if !defined(SCROLLDELTA) || !defined(SCROLLTIME)
|
||||
#define SCROLLDELTA 4
|
||||
#define SCROLLTIME 30
|
||||
#if __has_include("conf/displayST7789conf_custom.h")
|
||||
#include "conf/displayST7789conf_custom.h"
|
||||
#else
|
||||
#if DSP_MODEL==DSP_ST7789
|
||||
#include "conf/displayST7789conf.h"
|
||||
#else
|
||||
#include "conf/displayST7789_240conf.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define PLMITEMS 11
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 22
|
||||
#define TFT_FULLTIME 1
|
||||
|
||||
#define TITLE_TOP1 TFT_FRAMEWDT + META_SIZE * TFT_LINEHGHT + 8
|
||||
#define TITLE_TOP2 TFT_FRAMEWDT + (META_SIZE+2) * TFT_LINEHGHT + 8
|
||||
#define BOOT_PRG_COLOR 0xE68B
|
||||
#define BOOT_TXT_COLOR 0xFFFF
|
||||
#define PINK 0xF97F
|
||||
|
||||
class DspCore: public Adafruit_ST7789 {
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
uint16_t clockY;
|
||||
void initD(uint16_t &screenwidth, uint16_t &screenheight);
|
||||
void apScreen();
|
||||
void drawLogo();
|
||||
void clearDsp();
|
||||
void centerText(const char* text, uint16_t y, uint16_t fg, uint16_t bg);
|
||||
void rightText(const char* text, uint16_t y, uint16_t fg, uint16_t bg, bool fliprect=false, uint16_t delta = 0);
|
||||
void set_TextSize(uint8_t s);
|
||||
void set_TextColor(uint16_t fg, uint16_t bg);
|
||||
void set_Cursor(int16_t x, int16_t y);
|
||||
void printText(const char* txt);
|
||||
void printClock(const char* timestr);
|
||||
void printClock(struct tm timeinfo, bool dots, bool redraw = false);
|
||||
void displayHeapForDebug();
|
||||
void drawVolumeBar(bool withNumber);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
|
||||
void clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg);
|
||||
void frameTitle(const char* str);
|
||||
void rssi(const char* str);
|
||||
void ip(const char* str);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
virtual void startWrite(void);
|
||||
virtual void endWrite(void);
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
private:
|
||||
uint16_t swidth, sheight;
|
||||
char oldTimeBuf[20];
|
||||
uint16_t wot, hot;
|
||||
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
41
yoRadio/src/displays/dspcore.h
Normal file
41
yoRadio/src/displays/dspcore.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef dspcore_h
|
||||
#define dspcore_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#if DSP_MODEL==DSP_DUMMY
|
||||
#define DUMMYDISPLAY
|
||||
#define DSP_NOT_FLIPPED
|
||||
#include "tools/l10n.h"
|
||||
#elif DSP_MODEL==DSP_ST7735
|
||||
#include "displayST7735.h"
|
||||
#elif DSP_MODEL==DSP_SSD1306 || DSP_MODEL==DSP_SSD1306x32
|
||||
#include "displaySSD1306.h"
|
||||
#elif DSP_MODEL==DSP_NOKIA5110
|
||||
#include "displayN5110.h"
|
||||
#elif DSP_MODEL==DSP_ST7789 || DSP_MODEL==DSP_ST7789_240
|
||||
#include "displayST7789.h"
|
||||
#elif DSP_MODEL==DSP_SH1106
|
||||
#include "displaySH1106.h"
|
||||
#elif DSP_MODEL==DSP_1602I2C || DSP_MODEL==DSP_2004I2C
|
||||
#include "displayLC1602.h"
|
||||
#elif DSP_MODEL==DSP_SSD1327
|
||||
#include "displaySSD1327.h"
|
||||
#elif DSP_MODEL==DSP_ILI9341
|
||||
#include "displayILI9341.h"
|
||||
#elif DSP_MODEL==DSP_SSD1305 || DSP_MODEL==DSP_SSD1305I2C
|
||||
#include "displaySSD1305.h"
|
||||
#elif DSP_MODEL==DSP_SH1107
|
||||
#include "displaySH1106.h"
|
||||
#elif DSP_MODEL==DSP_1602 || DSP_MODEL==DSP_2004
|
||||
#include "displayLC1602.h"
|
||||
#elif DSP_MODEL==DSP_GC9106
|
||||
#include "displayGC9106.h"
|
||||
#elif DSP_MODEL==DSP_CUSTOM
|
||||
#include "displayCustom.h"
|
||||
#elif DSP_MODEL==DSP_ILI9225
|
||||
#include "displayILI9225.h"
|
||||
#endif
|
||||
|
||||
//extern DspCore dsp;
|
||||
|
||||
#endif
|
||||
@@ -16,7 +16,7 @@ const uint8_t DS_DIGI15pt7bBitmaps[] PROGMEM = {
|
||||
0xF8, 0x3F, 0x07, 0xDF, 0x77, 0xF5, 0xFF, 0x00, 0x7F, 0xC7, 0xF4, 0x7D,
|
||||
0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x03, 0x00, 0x20, 0x00, 0x00, 0x80,
|
||||
0x30, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0x60, 0x04, 0x00, 0x00, 0x7F,
|
||||
0xD7, 0xF7, 0x7D, 0xF0, 0xFE, 0x0F, 0xC1, 0xF8, 0x3E, 0x03, 0xBF, 0xAF,
|
||||
0xD7, 0xF7, 0x7D, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3E, 0x03, 0xBF, 0xAF,
|
||||
0xFA, 0xFE, 0xE0, 0x3E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xCE, 0x77, 0xF5,
|
||||
0xFF, 0x00, 0x7F, 0xD7, 0xF7, 0x7D, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3E,
|
||||
0x03, 0xBF, 0xAF, 0xF8, 0xFE, 0x80, 0x30, 0x0E, 0x01, 0xC0, 0x38, 0x07,
|
||||
@@ -54,7 +54,7 @@ const GFXglyph DS_DIGI15pt7bGlyphs[] PROGMEM = {
|
||||
};
|
||||
|
||||
const GFXfont DS_DIGI15pt7b PROGMEM = {
|
||||
(uint8_t *)DS_DIGI15pt7bBitmaps,
|
||||
(GFXglyph *)DS_DIGI15pt7bGlyphs, 0x20, 0x3A, 29 };
|
||||
(uint8_t *)DS_DIGI15pt7bBitmaps,
|
||||
(GFXglyph *)DS_DIGI15pt7bGlyphs, 0x20, 0x3A, 29 };
|
||||
|
||||
// Approx. 664 bytes
|
||||
|
||||
@@ -92,16 +92,16 @@ const GFXglyph DS_DIGI28pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x2E '.'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x2F '/'
|
||||
{ 20, 21, 35, 27, 3, -34 }, // 0x30 '0'
|
||||
{ 113, 4, 35, 14, 5, -34 }, // 0x31 '1'
|
||||
{ 113, 4, 35, 12, 5, -34 }, // 0x31 '1'
|
||||
{ 131, 21, 35, 27, 3, -34 }, // 0x32 '2'
|
||||
{ 224, 20, 35, 27, 4, -34 }, // 0x33 '3'
|
||||
{ 224, 20, 35, 26, 3, -34 }, // 0x33 '3'
|
||||
{ 312, 21, 34, 27, 3, -34 }, // 0x34 '4'
|
||||
{ 402, 21, 35, 27, 3, -34 }, // 0x35 '5'
|
||||
{ 495, 21, 35, 27, 3, -34 }, // 0x36 '6'
|
||||
{ 588, 20, 34, 27, 4, -34 }, // 0x37 '7'
|
||||
{ 588, 20, 34, 26, 3, -34 }, // 0x37 '7'
|
||||
{ 673, 21, 35, 27, 3, -34 }, // 0x38 '8'
|
||||
{ 766, 21, 35, 27, 3, -34 }, // 0x39 '9'
|
||||
{ 859, 4, 29, 12, 4, -28 } // 0x3A ':'
|
||||
{ 859, 4, 29, 11, 4, -28 } // 0x3A ':'
|
||||
};
|
||||
|
||||
const GFXfont DS_DIGI28pt7b PROGMEM = {
|
||||
|
||||
@@ -163,7 +163,7 @@ const uint8_t DS_DIGI42pt7bBitmaps[] PROGMEM = {
|
||||
};
|
||||
|
||||
const GFXglyph DS_DIGI42pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 0, 0, 19, 0, 1 }, // 0x20 ' '
|
||||
{ 0, 0, 0, 15, 0, 1 }, // 0x20 ' '
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x21 '!'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x22 '"'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x23 '#'
|
||||
@@ -180,7 +180,7 @@ const GFXglyph DS_DIGI42pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x2E '.'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x2F '/'
|
||||
{ 45, 31, 52, 40, 4, -51 }, // 0x30 '0'
|
||||
{ 247, 6, 51, 17, 6, -50 }, // 0x31 '1'
|
||||
{ 247, 6, 51, 15, 4, -50 }, // 0x31 '1'
|
||||
{ 286, 31, 52, 40, 4, -51 }, // 0x32 '2'
|
||||
{ 488, 30, 52, 39, 4, -51 }, // 0x33 '3'
|
||||
{ 683, 31, 52, 40, 4, -51 }, // 0x34 '4'
|
||||
|
||||
@@ -2,50 +2,64 @@ const uint8_t TinyFont5_Bitmaps[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0xE8, 0x00, 0xB4, 0x00, 0x57, 0xD5, 0xF5, 0x00, 0x7A,
|
||||
0x65, 0xE0, 0xA5, 0x4A, 0x00, 0x33, 0xE9, 0x70, 0xC0, 0x6A, 0x40, 0x95,
|
||||
0x80, 0xAA, 0x80, 0x5D, 0x00, 0x60, 0xE0, 0x80, 0x5E, 0x80, 0x69, 0x99,
|
||||
0x60, 0x59, 0x2E, 0x00, 0x69, 0x24, 0xF0, 0x69, 0x29, 0x60, 0x99, 0xF1,
|
||||
0x10, 0xF8, 0xE1, 0xE0, 0x68, 0xE9, 0x60, 0xF1, 0x24, 0x40, 0x69, 0x69,
|
||||
0x60, 0x69, 0x71, 0x60, 0xA0, 0x46, 0x64, 0x00, 0xE3, 0x80, 0x98, 0x00,
|
||||
0x69, 0x20, 0x20, 0x6B, 0xB8, 0x70, 0x69, 0x9F, 0x90, 0xE9, 0xE9, 0xE0,
|
||||
0x60, 0x59, 0x2E, 0x00, 0xF1, 0xF8, 0xF0, 0xF1, 0x61, 0xF0, 0x99, 0xF1,
|
||||
0x10, 0xF8, 0xF1, 0xF0, 0xF8, 0xF9, 0xF0, 0xF1, 0x24, 0x40, 0xF9, 0x69,
|
||||
0xF0, 0xF9, 0xF1, 0xF0, 0xA0, 0x46, 0x64, 0x00, 0xE3, 0x80, 0x98, 0x00,
|
||||
0xF9, 0x30, 0x20, 0x6B, 0xB8, 0x70, 0x69, 0x9F, 0x90, 0xE9, 0xE9, 0xE0,
|
||||
0x69, 0x89, 0x60, 0xE9, 0x99, 0xE0, 0xF8, 0xC8, 0xF0, 0xF8, 0xC8, 0x80,
|
||||
0x69, 0x8B, 0x60, 0x99, 0xF9, 0x90, 0xF8, 0x00, 0x11, 0x19, 0x60, 0x99,
|
||||
0xE9, 0x90, 0x88, 0x88, 0xF0, 0x8C, 0x63, 0xBA, 0x80, 0x99, 0xDB, 0x90,
|
||||
0x69, 0x99, 0x60, 0xE9, 0x9E, 0x80, 0x64, 0xA5, 0x26, 0x80, 0xE9, 0x9E,
|
||||
0x90, 0x68, 0x61, 0xE0, 0xE9, 0x24, 0x00, 0x99, 0x99, 0x60, 0x8C, 0x54,
|
||||
0x90, 0xE8, 0xF1, 0xF0, 0xE9, 0x24, 0x00, 0x99, 0x99, 0x60, 0x8C, 0x54,
|
||||
0xA2, 0x00, 0x8C, 0x6A, 0xE5, 0x00, 0x99, 0x69, 0x90, 0xB6, 0xA4, 0x00,
|
||||
0xF1, 0x68, 0xF0, 0xEA, 0xC0, 0xAD, 0x40, 0xD5, 0xC0, 0x54, 0x00, 0xE0,
|
||||
0x90, 0x17, 0x99, 0x70, 0x07, 0xEB, 0x5A, 0x80, 0x2B, 0x22, 0x00, 0xF0,
|
||||
0x89, 0xA8, 0x00, 0x16, 0x80, 0xF9, 0x99, 0xF0, 0x69, 0x9F, 0x90, 0xE8,
|
||||
0xF9, 0xE0, 0xE9, 0xE9, 0xE0, 0xF8, 0x88, 0x80, 0x32, 0x94, 0xAF, 0x80,
|
||||
0xF8, 0xC8, 0xF0, 0xAD, 0x5D, 0x5A, 0x80, 0x69, 0x29, 0x60, 0x99, 0xBD,
|
||||
0x90, 0xD1, 0xBD, 0x90, 0x99, 0xE9, 0x90, 0x79, 0x99, 0x90, 0x8C, 0x63,
|
||||
0xBA, 0x80, 0x99, 0xF9, 0x90, 0x69, 0x99, 0x60, 0xF9, 0x99, 0x90, 0xE9,
|
||||
0x9E, 0x80, 0x69, 0x89, 0x60, 0xE9, 0x24, 0x00, 0x99, 0x71, 0x60, 0x75,
|
||||
0x6A, 0xE2, 0x00, 0x99, 0x69, 0x90, 0x94, 0xA5, 0x2F, 0x84, 0x00, 0x99,
|
||||
0x9F, 0x10, 0x8C, 0x6B, 0x5F, 0x80, 0x8A, 0x2A, 0xAA, 0xFC, 0x10, 0xC3,
|
||||
0x92, 0x97, 0x00, 0x87, 0x99, 0x65, 0xE4, 0x00, 0x8E, 0x99, 0xE0, 0x69,
|
||||
0x39, 0x60, 0x95, 0x7B, 0x59, 0x00, 0x79, 0x97, 0x90, 0x80, 0x96, 0x9F,
|
||||
0x86, 0x96, 0x9F, 0x86
|
||||
0x90, 0x69, 0x9F, 0x90, 0xE9, 0xE9, 0xE0, 0x69, 0x89, 0x60, 0xE9, 0x99,
|
||||
0xE0, 0xF8, 0xC8, 0xF0, 0xF8, 0xC8, 0x80, 0x69, 0x8B, 0x60, 0x99, 0x9F,
|
||||
0x90, 0x44, 0x44, 0x40, 0x11, 0x19, 0x60, 0x99, 0xE9, 0x90, 0x88, 0x88,
|
||||
0xF0, 0x8C, 0x63, 0xBA, 0x80, 0x99, 0xDB, 0x90, 0x69, 0x99, 0x60, 0xE9,
|
||||
0x9E, 0x80, 0x64, 0xA5, 0x26, 0x80, 0xE9, 0x9E, 0x90, 0xE8, 0xF1, 0xF0,
|
||||
0xE4, 0x44, 0x40, 0x99, 0x99, 0x60, 0x8C, 0x54, 0xA2, 0x00, 0x8C, 0x6A,
|
||||
0xE5, 0x00, 0x99, 0x69, 0x90, 0x55, 0x52, 0x20, 0xF1, 0x68, 0xF0, 0x2B,
|
||||
0x22, 0x00, 0xF0, 0x89, 0xA8, 0x00, 0x16, 0x80, 0xF9, 0x99, 0xF0, 0xE9,
|
||||
0x9E, 0x80, 0x69, 0x89, 0x60, 0xE9, 0x24, 0x00, 0x99, 0x71, 0xE0, 0x75,
|
||||
0x6A, 0xE2, 0x00, 0x99, 0x69, 0x90, 0xAA, 0xAA, 0xF0, 0x99, 0x97, 0x10,
|
||||
0x8C, 0x6B, 0x5F, 0x80, 0x8C, 0x6B, 0x5F, 0x00, 0xC6, 0x55, 0x60, 0x8E,
|
||||
0x6B, 0x5C, 0x80, 0x8E, 0x99, 0xE0, 0x69, 0x39, 0x60, 0x95, 0x7B, 0x59,
|
||||
0x00, 0x79, 0x97, 0x90, 0x69, 0x9F, 0x90, 0xE8, 0xF9, 0xE0, 0xE9, 0xE9,
|
||||
0xE0, 0xF8, 0x88, 0x80, 0x35, 0x55, 0xF0, 0xF8, 0xC8, 0xF0, 0xAD, 0x5D,
|
||||
0x5A, 0x80, 0x69, 0x29, 0x60, 0x99, 0xBD, 0x90, 0xD1, 0xBD, 0x90, 0x99,
|
||||
0xE9, 0x90, 0x79, 0x99, 0x90, 0x8C, 0x63, 0xBA, 0x80, 0x99, 0xF9, 0x90,
|
||||
0x69, 0x99, 0x60, 0xF9, 0x99, 0x90, 0xE9, 0x9E, 0x80, 0x69, 0x89, 0x60,
|
||||
0xE9, 0x24, 0x00, 0x99, 0x71, 0x60, 0x75, 0x6A, 0xE2, 0x00, 0x99, 0x69,
|
||||
0x90, 0xAA, 0xAA, 0xF0, 0x99, 0x9F, 0x10, 0x8C, 0x6B, 0x5F, 0x80, 0x8C,
|
||||
0x6B, 0x5F, 0x00, 0x00, 0xC6, 0x55, 0x60, 0x8E, 0x6B, 0x5C, 0x80, 0x8E,
|
||||
0x99, 0xE0, 0x69, 0x39, 0x60, 0x95, 0x7B, 0x59, 0x00, 0x79, 0x97, 0x90,
|
||||
0x69, 0x9F, 0x90, 0xE8, 0xF9, 0xE0, 0xE9, 0xE9, 0xE0, 0xF8, 0x88, 0x80,
|
||||
0x35, 0x55, 0xF0, 0xF8, 0xE8, 0xF0, 0xAD, 0x5D, 0x5A, 0x80, 0x69, 0x29,
|
||||
0x60, 0x99, 0xBD, 0x90, 0xB9, 0xBD, 0x90, 0x99, 0xE9, 0x90, 0x79, 0x99,
|
||||
0x90, 0x8C, 0x63, 0xBA, 0x80, 0x99, 0x9F, 0x90, 0x69, 0x99, 0x60, 0xF9,
|
||||
0x99, 0x90, 0x96, 0x9F, 0x86, 0x96, 0x9F, 0x86
|
||||
};
|
||||
|
||||
const GFXglyph TinyFont5_Glyphs[] PROGMEM = {
|
||||
{ 0, 3, 5, 3, 0, -5 }, // 0x20 ' '
|
||||
{ 3, 1, 5, 2, 0, -5 }, // 0x21 '!'
|
||||
{ 5, 3, 2, 4, 0, -5 }, // 0x22 '"'
|
||||
{ 7, 5, 5, 6, 0, -4 }, // 0x23 '#'
|
||||
{ 0, 4, 5, 5, 0, -5 }, // 0x20 ' '
|
||||
{ 3, 1, 5, 5, 1, -5 }, // 0x21 '!'
|
||||
{ 5, 3, 2, 5, 1, -5 }, // 0x22 '"'
|
||||
{ 7, 5, 5, 5, 0, -5 }, // 0x23 '#'
|
||||
{ 11, 4, 5, 5, 0, -5 }, // 0x24 '$'
|
||||
{ 14, 3, 5, 4, 0, -5 }, // 0x25 '%'
|
||||
{ 14, 3, 5, 5, 1, -5 }, // 0x25 '%'
|
||||
{ 17, 4, 5, 5, 0, -5 }, // 0x26 '&'
|
||||
{ 20, 1, 2, 2, 0, -5 }, // 0x27 '''
|
||||
{ 21, 2, 5, 4, 0, -5 }, // 0x28 '('
|
||||
{ 23, 2, 5, 4, 0, -5 }, // 0x29 ')'
|
||||
{ 25, 3, 3, 4, 0, -4 }, // 0x2A '*'
|
||||
{ 27, 3, 3, 4, 0, -4 }, // 0x2B '+'
|
||||
{ 29, 2, 2, 3, 0, -1 }, // 0x2C ','
|
||||
{ 30, 3, 1, 4, 0, -3 }, // 0x2D '-'
|
||||
{ 31, 1, 1, 2, 0, -1 }, // 0x2E '.'
|
||||
{ 32, 2, 5, 4, 0, -5 }, // 0x2F '/'
|
||||
{ 20, 1, 2, 5, 1, -5 }, // 0x27 '''
|
||||
{ 21, 2, 5, 5, 1, -5 }, // 0x28 '('
|
||||
{ 23, 2, 5, 5, 1, -5 }, // 0x29 ')'
|
||||
{ 25, 3, 3, 5, 1, -4 }, // 0x2A '*'
|
||||
{ 27, 3, 3, 5, 1, -4 }, // 0x2B '+'
|
||||
{ 29, 2, 2, 5, 1, -1 }, // 0x2C ','
|
||||
{ 30, 3, 1, 5, 1, -3 }, // 0x2D '-'
|
||||
{ 31, 1, 1, 5, 2, -1 }, // 0x2E '.'
|
||||
{ 32, 2, 5, 5, 1, -5 }, // 0x2F '/'
|
||||
{ 34, 4, 5, 5, 0, -5 }, // 0x30 '0'
|
||||
{ 37, 3, 5, 4, 0, -5 }, // 0x31 '1'
|
||||
{ 37, 3, 5, 5, 1, -5 }, // 0x31 '1'
|
||||
{ 40, 4, 5, 5, 0, -5 }, // 0x32 '2'
|
||||
{ 43, 4, 5, 5, 0, -5 }, // 0x33 '3'
|
||||
{ 46, 4, 5, 5, 0, -5 }, // 0x34 '4'
|
||||
@@ -54,11 +68,11 @@ const GFXglyph TinyFont5_Glyphs[] PROGMEM = {
|
||||
{ 55, 4, 5, 5, 0, -5 }, // 0x37 '7'
|
||||
{ 58, 4, 5, 5, 0, -5 }, // 0x38 '8'
|
||||
{ 61, 4, 5, 5, 0, -5 }, // 0x39 '9'
|
||||
{ 64, 1, 3, 2, 0, -4 }, // 0x3A ':'
|
||||
{ 65, 2, 4, 3, 0, -4 }, // 0x3B ';'
|
||||
{ 66, 2, 3, 3, 0, -4 }, // 0x3C '<'
|
||||
{ 68, 3, 3, 4, 0, -4 }, // 0x3D '='
|
||||
{ 70, 2, 3, 3, 0, -4 }, // 0x3E '>'
|
||||
{ 64, 1, 3, 5, 2, -4 }, // 0x3A ':'
|
||||
{ 65, 2, 4, 5, 1, -4 }, // 0x3B ';'
|
||||
{ 66, 2, 3, 5, 1, -4 }, // 0x3C '<'
|
||||
{ 68, 3, 3, 5, 1, -3 }, // 0x3D '='
|
||||
{ 70, 2, 3, 5, 1, -4 }, // 0x3E '>'
|
||||
{ 72, 4, 5, 5, 0, -5 }, // 0x3F '?'
|
||||
{ 75, 4, 5, 5, 0, -5 }, // 0x40 '@'
|
||||
{ 78, 4, 5, 5, 0, -5 }, // 0x41 'A'
|
||||
@@ -69,127 +83,127 @@ const GFXglyph TinyFont5_Glyphs[] PROGMEM = {
|
||||
{ 93, 4, 5, 5, 0, -5 }, // 0x46 'F'
|
||||
{ 96, 4, 5, 5, 0, -5 }, // 0x47 'G'
|
||||
{ 99, 4, 5, 5, 0, -5 }, // 0x48 'H'
|
||||
{ 102, 1, 5, 2, 0, -5 }, // 0x49 'I'
|
||||
{ 102, 1, 5, 5, 1, -5 }, // 0x49 'I'
|
||||
{ 104, 4, 5, 5, 0, -5 }, // 0x4A 'J'
|
||||
{ 107, 4, 5, 5, 0, -5 }, // 0x4B 'K'
|
||||
{ 110, 4, 5, 5, 0, -5 }, // 0x4C 'L'
|
||||
{ 113, 5, 5, 6, 0, -5 }, // 0x4D 'M'
|
||||
{ 113, 5, 5, 5, 0, -5 }, // 0x4D 'M'
|
||||
{ 117, 4, 5, 5, 0, -5 }, // 0x4E 'N'
|
||||
{ 120, 4, 5, 5, 0, -5 }, // 0x4F 'O'
|
||||
{ 123, 4, 5, 5, 0, -5 }, // 0x50 'P'
|
||||
{ 126, 5, 5, 6, 0, -5 }, // 0x51 'Q'
|
||||
{ 126, 5, 5, 5, 0, -5 }, // 0x51 'Q'
|
||||
{ 130, 4, 5, 5, 0, -5 }, // 0x52 'R'
|
||||
{ 133, 4, 5, 5, 0, -5 }, // 0x53 'S'
|
||||
{ 136, 3, 5, 4, 0, -5 }, // 0x54 'T'
|
||||
{ 136, 3, 5, 5, 1, -5 }, // 0x54 'T'
|
||||
{ 139, 4, 5, 5, 0, -5 }, // 0x55 'U'
|
||||
{ 142, 5, 5, 6, 0, -5 }, // 0x56 'V'
|
||||
{ 146, 5, 5, 6, 0, -5 }, // 0x57 'W'
|
||||
{ 142, 5, 5, 5, 0, -5 }, // 0x56 'V'
|
||||
{ 146, 5, 5, 5, 0, -5 }, // 0x57 'W'
|
||||
{ 150, 4, 5, 5, 0, -5 }, // 0x58 'X'
|
||||
{ 153, 3, 5, 4, 0, -5 }, // 0x59 'Y'
|
||||
{ 153, 3, 5, 5, 1, -5 }, // 0x59 'Y'
|
||||
{ 156, 4, 5, 5, 0, -5 }, // 0x5A 'Z'
|
||||
{ 159, 2, 5, 3, 0, -5 }, // 0x5B '['
|
||||
{ 161, 2, 5, 3, 0, -5 }, // 0x5C '\'
|
||||
{ 163, 2, 5, 4, 0, -5 }, // 0x5D ']'
|
||||
{ 165, 3, 2, 4, 0, -5 }, // 0x5E '^'
|
||||
{ 167, 3, 1, 4, 0, -1 }, // 0x5F '_'
|
||||
{ 168, 2, 2, 3, 0, -5 }, // 0x60 '`'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x61 'a'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x62 'b'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x63 'c'
|
||||
{ 169, 4, 5, 5, 0, -5 }, // 0x64 'd'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x65 'e'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x66 'f'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x67 'g'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x68 'h'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x69 'i'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x6A 'j'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x6B 'k'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x6C 'l'
|
||||
{ 172, 5, 5, 6, 0, -5 }, // 0x6D 'm'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x6E 'n'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x6F 'o'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x70 'p'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x71 'q'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x72 'r'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x73 's'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x74 't'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x75 'u'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x76 'v'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x77 'w'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x78 'x'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x79 'y'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x7A 'z'
|
||||
{ 176, 3, 5, 4, 0, -5 }, // 0x7B '{'
|
||||
{ 179, 1, 4, 4, 0, -4 }, // 0x7C '|'
|
||||
{ 180, 3, 5, 4, 0, -5 }, // 0x7D '}'
|
||||
{ 183, 4, 3, 5, 0, -4 }, // 0x7E '~'
|
||||
{ 185, 4, 5, 5, 0, -5 }, // 0x7F 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x80 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x81 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x82 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x83 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x84 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x85 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x86 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x87 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x88 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x89 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x8A 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x8B 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x8C 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x8D 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x8E 'non-printable'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0x8F 'non-printable'
|
||||
{ 188, 4, 5, 5, 0, -5 }, // 0x90 'non-printable'
|
||||
{ 191, 4, 5, 5, 0, -5 }, // 0x91 'non-printable'
|
||||
{ 194, 4, 5, 5, 0, -5 }, // 0x92 'non-printable'
|
||||
{ 197, 4, 5, 5, 0, -5 }, // 0x93 'non-printable'
|
||||
{ 200, 5, 5, 6, 0, -5 }, // 0x94 'non-printable'
|
||||
{ 204, 4, 5, 5, 0, -5 }, // 0x95 'non-printable'
|
||||
{ 207, 5, 5, 6, 0, -5 }, // 0x96 'non-printable'
|
||||
{ 211, 4, 5, 5, 0, -5 }, // 0x97 'non-printable'
|
||||
{ 214, 4, 5, 5, 0, -5 }, // 0x98 'non-printable'
|
||||
{ 217, 4, 5, 5, 0, -5 }, // 0x99 'non-printable'
|
||||
{ 220, 4, 5, 4, 0, -5 }, // 0x9A 'non-printable'
|
||||
{ 223, 4, 5, 4, 0, -5 }, // 0x9B 'non-printable'
|
||||
{ 226, 5, 5, 6, 0, -5 }, // 0x9C 'non-printable'
|
||||
{ 230, 4, 5, 5, 0, -5 }, // 0x9D 'non-printable'
|
||||
{ 233, 4, 5, 5, 0, -5 }, // 0x9E 'non-printable'
|
||||
{ 236, 4, 5, 5, 0, -5 }, // 0x9F 'non-printable'
|
||||
{ 239, 4, 5, 5, 0, -5 }, // 0xA0 ' '
|
||||
{ 242, 4, 5, 5, 0, -5 }, // 0xA1 '¡'
|
||||
{ 245, 3, 5, 4, 0, -5 }, // 0xA2 '¢'
|
||||
{ 248, 4, 5, 5, 0, -5 }, // 0xA3 '£'
|
||||
{ 251, 5, 5, 6, 0, -5 }, // 0xA4 '¤'
|
||||
{ 255, 4, 5, 5, 0, -5 }, // 0xA5 '¥'
|
||||
{ 258, 5, 6, 6, 0, -5 }, // 0xA6 '¦'
|
||||
{ 263, 4, 5, 5, 0, -5 }, // 0xA7 '§'
|
||||
{ 266, 5, 5, 6, 0, -5 }, // 0xA8 '¨'
|
||||
{ 270, 6, 6, 7, 0, -5 }, // 0xA9 '©'
|
||||
{ 275, 5, 5, 6, 0, -5 }, // 0xAA 'ª'
|
||||
{ 279, 6, 5, 7, 0, -5 }, // 0xAB '«'
|
||||
{ 284, 4, 5, 5, 0, -5 }, // 0xAC '¬'
|
||||
{ 287, 4, 5, 5, 0, -5 }, // 0xAD 'non-printable'
|
||||
{ 290, 5, 5, 6, 0, -5 }, // 0xAE '®'
|
||||
{ 294, 4, 5, 5, 0, -5 }, // 0xAF '¯'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB0 '°'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB1 '±'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB2 '²'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB3 '³'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB4 '´'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB5 'µ'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB6 '¶'
|
||||
{ 297, 1, 1, 2, 0, -3 }, // 0xB7 '·'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB8 '¸'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xB9 '¹'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xBA 'º'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xBB '»'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xBC '¼'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xBD '½'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xBE '¾'
|
||||
{ 0, 0, 0, 0, 0, 0 }, // 0xBF '¿'
|
||||
{ 298, 4, 6, 5, 0, -5 }, // 0xC0 'À'
|
||||
{ 301, 4, 6, 5, 0, -5 } // 0xC1 'Á'
|
||||
{ 159, 2, 5, 5, 1, -5 }, // 0x5B '['
|
||||
{ 161, 2, 5, 5, 1, -5 }, // 0x5C '\'
|
||||
{ 163, 2, 5, 5, 1, -5 }, // 0x5D ']'
|
||||
{ 165, 3, 2, 5, 1, -5 }, // 0x5E '^'
|
||||
{ 167, 3, 1, 5, 1, -1 }, // 0x5F '_'
|
||||
{ 168, 2, 2, 5, 1, -5 }, // 0x60 '`'
|
||||
{ 169, 4, 5, 5, 0, -5 }, // 0x61 'a'
|
||||
{ 172, 4, 5, 5, 0, -5 }, // 0x62 'b'
|
||||
{ 175, 4, 5, 5, 0, -5 }, // 0x63 'c'
|
||||
{ 178, 4, 5, 5, 0, -5 }, // 0x64 'd'
|
||||
{ 181, 4, 5, 5, 0, -5 }, // 0x65 'e'
|
||||
{ 184, 4, 5, 5, 0, -5 }, // 0x66 'f'
|
||||
{ 187, 4, 5, 5, 0, -5 }, // 0x67 'g'
|
||||
{ 190, 4, 5, 5, 0, -5 }, // 0x68 'h'
|
||||
{ 193, 4, 5, 5, 0, -5 }, // 0x69 'i'
|
||||
{ 196, 4, 5, 5, 0, -5 }, // 0x6A 'j'
|
||||
{ 199, 4, 5, 5, 0, -5 }, // 0x6B 'k'
|
||||
{ 202, 4, 5, 5, 0, -5 }, // 0x6C 'l'
|
||||
{ 205, 5, 5, 5, 0, -5 }, // 0x6D 'm'
|
||||
{ 209, 4, 5, 5, 0, -5 }, // 0x6E 'n'
|
||||
{ 212, 4, 5, 5, 0, -5 }, // 0x6F 'o'
|
||||
{ 215, 4, 5, 5, 0, -5 }, // 0x70 'p'
|
||||
{ 218, 5, 5, 5, 0, -5 }, // 0x71 'q'
|
||||
{ 222, 4, 5, 5, 0, -5 }, // 0x72 'r'
|
||||
{ 225, 4, 5, 5, 0, -5 }, // 0x73 's'
|
||||
{ 228, 4, 5, 5, 0, -5 }, // 0x74 't'
|
||||
{ 231, 4, 5, 5, 0, -5 }, // 0x75 'u'
|
||||
{ 234, 5, 5, 5, 0, -5 }, // 0x76 'v'
|
||||
{ 238, 5, 5, 5, 0, -5 }, // 0x77 'w'
|
||||
{ 242, 4, 5, 5, 0, -5 }, // 0x78 'x'
|
||||
{ 245, 4, 5, 5, 0, -5 }, // 0x79 'y'
|
||||
{ 248, 4, 5, 5, 0, -5 }, // 0x7A 'z'
|
||||
{ 251, 3, 5, 5, 1, -5 }, // 0x7B '{'
|
||||
{ 254, 1, 4, 5, 1, -4 }, // 0x7C '|'
|
||||
{ 255, 3, 5, 5, 1, -5 }, // 0x7D '}'
|
||||
{ 258, 4, 3, 5, 0, -4 }, // 0x7E '~'
|
||||
{ 260, 4, 5, 5, 0, -5 }, // 0x7F 'non-printable'
|
||||
{ 263, 4, 5, 5, 0, -5 }, // 0x80 'non-printable'
|
||||
{ 266, 4, 5, 5, 0, -5 }, // 0x81 'non-printable'
|
||||
{ 269, 3, 5, 5, 1, -5 }, // 0x82 'non-printable'
|
||||
{ 272, 4, 5, 5, 0, -5 }, // 0x83 'non-printable'
|
||||
{ 275, 5, 5, 5, 0, -5 }, // 0x84 'non-printable'
|
||||
{ 279, 4, 5, 5, 0, -5 }, // 0x85 'non-printable'
|
||||
{ 282, 4, 5, 5, 0, -5 }, // 0x86 'non-printable'
|
||||
{ 285, 4, 5, 5, 0, -5 }, // 0x87 'non-printable'
|
||||
{ 288, 5, 5, 5, 0, -5 }, // 0x88 'non-printable'
|
||||
{ 292, 5, 5, 5, 0, -5 }, // 0x89 'non-printable'
|
||||
{ 296, 4, 5, 5, 0, -5 }, // 0x8A 'non-printable'
|
||||
{ 299, 5, 5, 5, 0, -5 }, // 0x8B 'non-printable'
|
||||
{ 303, 4, 5, 5, 0, -5 }, // 0x8C 'non-printable'
|
||||
{ 306, 4, 5, 5, 0, -5 }, // 0x8D 'non-printable'
|
||||
{ 309, 5, 5, 5, 0, -5 }, // 0x8E 'non-printable'
|
||||
{ 313, 4, 5, 5, 0, -5 }, // 0x8F 'non-printable'
|
||||
{ 316, 4, 5, 5, 0, -5 }, // 0x90 'non-printable'
|
||||
{ 319, 4, 5, 5, 0, -5 }, // 0x91 'non-printable'
|
||||
{ 322, 4, 5, 5, 0, -5 }, // 0x92 'non-printable'
|
||||
{ 325, 4, 5, 5, 0, -5 }, // 0x93 'non-printable'
|
||||
{ 328, 4, 5, 5, 0, -5 }, // 0x94 'non-printable'
|
||||
{ 331, 4, 5, 5, 0, -5 }, // 0x95 'non-printable'
|
||||
{ 334, 5, 5, 5, 0, -5 }, // 0x96 'non-printable'
|
||||
{ 338, 4, 5, 5, 0, -5 }, // 0x97 'non-printable'
|
||||
{ 341, 4, 5, 5, 0, -5 }, // 0x98 'non-printable'
|
||||
{ 344, 4, 5, 5, 0, -5 }, // 0x99 'non-printable'
|
||||
{ 347, 4, 5, 4, 0, -5 }, // 0x9A 'non-printable'
|
||||
{ 350, 4, 5, 4, 0, -5 }, // 0x9B 'non-printable'
|
||||
{ 353, 5, 5, 5, 0, -5 }, // 0x9C 'non-printable'
|
||||
{ 357, 4, 5, 5, 0, -5 }, // 0x9D 'non-printable'
|
||||
{ 360, 4, 5, 5, 0, -5 }, // 0x9E 'non-printable'
|
||||
{ 363, 4, 5, 5, 0, -5 }, // 0x9F 'non-printable'
|
||||
{ 366, 4, 5, 5, 0, -5 }, // 0xA0 ' '
|
||||
{ 369, 4, 5, 5, 0, -5 }, // 0xA1 '¡'
|
||||
{ 372, 3, 5, 5, 1, -5 }, // 0xA2 '¢'
|
||||
{ 375, 4, 5, 5, 0, -5 }, // 0xA3 '£'
|
||||
{ 378, 5, 5, 5, 0, -5 }, // 0xA4 '¤'
|
||||
{ 382, 4, 5, 5, 0, -5 }, // 0xA5 '¥'
|
||||
{ 385, 4, 5, 5, 0, -5 }, // 0xA6 '¦'
|
||||
{ 388, 4, 5, 5, 0, -5 }, // 0xA7 '§'
|
||||
{ 391, 5, 5, 5, 0, -5 }, // 0xA8 '¨'
|
||||
{ 395, 5, 6, 5, 0, -5 }, // 0xA9 '©'
|
||||
{ 400, 4, 5, 5, 0, -5 }, // 0xAA 'ª'
|
||||
{ 403, 5, 5, 5, 0, -5 }, // 0xAB '«'
|
||||
{ 407, 4, 5, 5, 0, -5 }, // 0xAC '¬'
|
||||
{ 410, 4, 5, 5, 0, -5 }, // 0xAD 'non-printable'
|
||||
{ 413, 5, 5, 5, 0, -5 }, // 0xAE '®'
|
||||
{ 417, 4, 5, 5, 0, -5 }, // 0xAF '¯'
|
||||
{ 420, 4, 5, 5, 0, -5 }, // 0xB0 '°'
|
||||
{ 423, 4, 5, 5, 0, -5 }, // 0xB1 '±'
|
||||
{ 426, 4, 5, 5, 0, -5 }, // 0xB2 '²'
|
||||
{ 429, 4, 5, 5, 0, -5 }, // 0xB3 '³'
|
||||
{ 432, 4, 5, 5, 0, -5 }, // 0xB4 '´'
|
||||
{ 435, 4, 5, 5, 0, -5 }, // 0xB5 'µ'
|
||||
{ 438, 5, 5, 5, 0, -5 }, // 0xB6 '¶'
|
||||
{ 442, 4, 5, 5, 0, -5 }, // 0xB7 '·'
|
||||
{ 445, 4, 5, 5, 0, -5 }, // 0xB8 '¸'
|
||||
{ 448, 4, 5, 5, 0, -5 }, // 0xB9 '¹'
|
||||
{ 451, 4, 5, 5, 0, -5 }, // 0xBA 'º'
|
||||
{ 454, 4, 5, 5, 0, -5 }, // 0xBB '»'
|
||||
{ 457, 5, 5, 5, 0, -5 }, // 0xBC '¼'
|
||||
{ 461, 4, 5, 5, 0, -5 }, // 0xBD '½'
|
||||
{ 464, 4, 5, 5, 0, -5 }, // 0xBE '¾'
|
||||
{ 467, 4, 5, 5, 0, -5 }, // 0xBF '¿'
|
||||
{ 470, 4, 6, 5, 0, -5 }, // 0xC0 'À'
|
||||
{ 473, 4, 6, 5, 0, -5 } // 0xC1 'Á'
|
||||
};
|
||||
|
||||
const GFXfont TinyFont5 PROGMEM = {(uint8_t *) TinyFont5_Bitmaps, (GFXglyph *)TinyFont5_Glyphs, 0x20, 0xC1, 5};
|
||||
const GFXfont TinyFont5 PROGMEM = {(uint8_t *) TinyFont5_Bitmaps, (GFXglyph *)TinyFont5_Glyphs, 0x20, 0xC1, 5};
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
|
||||
/*******************************************************************************
|
||||
* generated by lcd-image-converter rev.030b30d from 2019-03-17 01:38:34 +0500
|
||||
* image
|
||||
* filename: unsaved
|
||||
* name: bl40
|
||||
*
|
||||
* preset name: Grayscale 8
|
||||
* data block size: 8 bit(s), uint8_t
|
||||
* RLE compression enabled: no
|
||||
* conversion type: Grayscale, not_used not_used
|
||||
* split to rows: yes
|
||||
* bits per pixel: 8
|
||||
*
|
||||
* preprocess:
|
||||
* main scan direction: top_to_bottom
|
||||
* line scan direction: forward
|
||||
* inverse: no
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
typedef struct {
|
||||
const uint8_t *data;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t dataSize;
|
||||
} tImage;
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
static const uint8_t bootlogobw[6336] PROGMEM = {
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▓▒∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙▒▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙▒▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙░▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙█▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙∙∙░█▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓▓▓▓▓░∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙░███▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░░░∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒░░∙∙∙▒▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒∙∙∙∙∙∙∙∙∙░∙∙▓▒∙∙∙∙░▓▓▓▓▓▓▓▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░░∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙▒▒░░░░▒▒░∙∙∙∙∙∙∙∙∙∙▒∙∙∙░▓▒▒▓▓▓▒▒▒▒▒▒▒▒▒▓▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒░∙░▒∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙▒░∙∙∙∙∙░░░▒∙∙∙∙∙∙∙∙∙▓∙∙∙∙∙▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▓░∙∙∙▓∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙░▒∙∙∙∙∙∙▒∙∙∙▓∙∙∙∙∙∙∙∙▓░∙∙∙░█░░▒▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░∙∙∙∙∙▒▓░∙∙∙∙▓∙∙∙
|
||||
// ∙∙∙∙∙∙∙▒∙∙∙∙∙∙▒∙∙∙∙∙▓░∙∙∙∙∙∙▓▒∙∙∙▒▓▓░░▒▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓█∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙∙∙▒▓░∙∙∙∙∙▓∙∙∙
|
||||
// ∙∙∙∙∙∙▓∙∙∙∙∙∙▒∙∙∙∙∙∙▒▒∙∙∙∙∙▒▓∙∙∙█▓▓▓░░▒▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙░░∙∙∙∙▒▓▒∙∙∙∙▒▓▒∙∙∙∙∙▒░∙∙░
|
||||
// ∙∙∙∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙▒▒∙∙∙∙∙▓░∙∙▓▓▓▓▓░░▒▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙∙░▓▓∙∙∙∙░▓▓∙∙∙∙∙∙▓∙∙▒∙
|
||||
// ∙∙∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙∙▓▒∙∙∙∙▓▓∙∙▒█▓▓▓▓░░▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓∙∙∙∙∙∙∙∙▓▓░∙∙∙∙▓▓░∙∙∙∙▓▓▒∙∙∙∙∙░░∙░∙∙
|
||||
// ∙∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙∙∙▓░∙∙∙▒▓░∙░█▓▓▓▓▒░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓░▒▒∙∙∙∙▒▓▓∙∙∙∙▒▓▒∙∙∙∙▓▓▓∙∙∙∙∙∙▒∙▒∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙░∙∙∙∙∙∙∙∙∙░▓∙∙∙∙▓▓∙∙████▓▓░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒░░▒▒░▓∙∙∙∙░▒▓∙∙∙∙∙▓▓∙∙∙∙▒░▓▓∙∙∙∙∙▒▓░∙∙∙∙
|
||||
// ∙∙▒∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙▒▓▒∙▓█████▒░▒▓▓▓▓▓▓█▒░∙░▒█▓▓▓▓▒▒▒░▒▒▒▒░░░∙∙∙▒░▓▓∙∙∙∙▓▓▒∙∙∙▒∙▒▓░∙∙∙∙░∙∙∙∙∙∙∙
|
||||
// ∙░∙∙∙∙∙▓∙∙∙∙∙∙∙∙∙∙∙▓▒∙∙░▓▓∙∙█████▓░▒█▓▓▓▓█░∙∙∙∙∙∙∙∙▓▓▓▒░░▒▒▒▒▒░░▓∙∙∙∙▓▓∙∙∙∙▒▓▓∙∙∙∙∙∙▒▓∙∙∙∙∙░∙∙∙∙∙∙∙
|
||||
// ∙▒∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙▓▓▒∙▓█████░▒████▓█∙∙∙∙∙░▒∙∙∙∙▓▒░░▓▓▒▒▒░░▒▓░∙░▒▓▒∙∙∙░▓▓░∙∙∙░∙∙░▓∙∙∙░░∙∙∙∙∙∙∙∙
|
||||
// ░∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙▓▒∙∙░▓▓∙∙████▓░▒██████∙∙∙∙∙▒▓∙∙∙∙∙░░░▓▓▓▓▓░░░▒▒▓▒∙▓▓∙∙∙∙▒▓▓∙∙∙▒∙∙∙∙▓░∙▒░∙∙∙∙∙∙∙∙∙
|
||||
// ░∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙▓▓▒∙░███▒░███████▓▒░░░░▓▒∙∙∙∙∙▓▒▒▓▓▓▓▒░░▒▒▒▓∙▒▓░∙∙∙▒∙▓▒∙∙▒∙∙∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙░∙∙∙∙∙∙∙∙∙∙∙▓░∙∙░▓▓∙∙▒▒▒▓████████░░∙∙∙░▓▓∙∙∙∙∙▓▓░▓▓▓▓▓░░░▓▓▒▒∙▓▓∙∙∙▒∙∙▓∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙▓▓▒∙∙██████████▓░▒∙∙∙∙▒▓▒∙∙∙∙▓▓▓∙▓▓▓▓▒░░▒▓▓▒▓∙▓░∙∙▒∙∙∙▓▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙░∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙░▓▓∙∙∙█████████▓░▒▒∙∙∙░▓▓∙∙∙∙▒▓▓░∙▒▓▓▓▒░░▓▓▒▓▓░▓∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙░∙∙∙∙∙∙∙∙∙░▓∙∙∙∙▓▓▒∙∙░████████▓░░█▒░░░▒▒▒░░░░▒▒▒░░▒▓▓▒░░▒▓▒▓▓▓▒▒▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙░∙∙∙∙∙∙∙∙∙░▓░∙∙∙░▓▓∙∙∙░████████░░▓████▓░░████▓▓░░▓▓▓▓▒▓░░▓▒▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙░∙∙∙∙∙∙∙∙░▓∙∙∙∙∙▒▓▒∙∙∙▒▓██████░░▒█████░░▓███▒█▓░▓███▒▓▒░▓▒▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙░∙∙∙∙∙∙▒▒∙∙∙∙∙░▓▓∙∙∙∙▒▓▓▓███▒░░▓████▒░░███▒██▓░▓██▒▓▓░▒▒▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙▒∙∙∙∙░▒░∙∙∙∙∙∙▓▓░∙∙∙∙▒▓▓▓▓██░░▒████▓░░▓██▓████░▒▒▒▓█▓░▒▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙░░▒▒░∙∙∙∙∙∙∙░▓▒∙∙∙∙∙▒▓▓▓▓▓▓░░▓████▓▒░██▓▓█████▓▓███░░▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▓∙∙∙∙∙∙▒▓▓▓▓▓▓░░▓███▒█▒░█▓▓█████████▓▒░▓███▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▓∙∙∙∙∙∙∙▒▓▓▓▓▓▓░░█▓█▒██▓░░██████████▓▓▒░██████▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓░∙∙∙∙∙∙∙░▓▓▓▓▓▓▒░▓▓▒▓██████████████▒██░▓█████████▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒∙∙∙∙∙∙∙∙░▓▓▓▓▓▓▓▒▒▒▓▓░∙∙∙∙∙∙∙∙∙∙∙∙▒∙∙▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒∙∙∙∙∙∙∙∙∙∙▓▓▓▓▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙∙∙∙∙▒∙∙∙▓░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙░▓∙∙∙∙∙∙∙∙∙∙∙▓▒▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙∙∙∙▒∙∙∙▒▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▓▓▓▓▓▓▓▓▓░∙∙∙∙∙∙∙∙▓∙∙∙∙▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙▓▓▒∙∙∙∙∙∙∙░▒∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▓▓▓▓▓▓▓█∙∙∙∙∙∙∙▓∙∙∙∙▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ░▓▓▓∙∙∙∙∙∙▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▒▒▒▓▓▓▓▓▓▓∙∙∙∙∙▒∙∙∙∙∙▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ▒▓▓░∙∙∙∙∙▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▓▒▒▒▒▒▒▒▒▓▓▓▓▓▓░∙∙░▒∙∙∙∙▓∙∙∙∙∙∙∙∙∙▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙▓▓▒∙∙░▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓█░▓∙∙∙∙░∙∙∙∙∙∙∙▒███▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙▒▒▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▒▒███▒▒▓███████████∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▒▒▓▓▓▒▓▓▓▓▓▓▓██████∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒░▓▒▒▓▓▓▓▓▓▓▓▓█████∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓███░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓█∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▒∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
// ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙░▒▒▒▒▒▒▒▒▒▓▓▓▒░∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x68, 0xb0, 0xcb, 0xc9, 0xc4, 0x83, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x70, 0xa7, 0xa7, 0xa4, 0x8f, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xcb, 0xc4, 0xc4, 0xc4, 0xc3, 0xc2, 0xc0, 0xca, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xb4, 0xa6, 0xa3, 0xa1, 0x9e, 0x9b, 0x9a, 0xa2, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc4, 0xbb, 0xbe, 0xc0, 0xc2, 0xc4, 0xc4, 0xc2, 0xc2, 0xc4, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xb6, 0xad, 0xab, 0xa8, 0xa7, 0xa3, 0xa0, 0x9e, 0x9b, 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xb5, 0xb7, 0xb9, 0xbb, 0xbe, 0xc0, 0xc2, 0xc4, 0xc5, 0xc3, 0xcd, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xc4, 0xb5, 0xb3, 0xb0, 0xae, 0xaa, 0xa8, 0xa6, 0xa3, 0xa1, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xbf, 0xb1, 0xb2, 0xb4, 0xb7, 0xba, 0xbc, 0xbe, 0xc0, 0xc3, 0xc4, 0xc5, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0xb9, 0xb6, 0xb5, 0xb2, 0xaf, 0xad, 0xaa, 0xa8, 0xa5, 0xa2, 0xac, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xb4, 0xac, 0xaf, 0xb1, 0xb3, 0xb5, 0xb8, 0xba, 0xbc, 0xbe, 0xc1, 0xc3, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0xbb, 0xbb, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xaf, 0xac, 0xaa, 0xa8, 0xac, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xad, 0xa7, 0xaa, 0xac, 0xaf, 0xb2, 0xb3, 0xb5, 0xb8, 0xba, 0xbc, 0xbe, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xbe, 0xbd, 0xbc, 0xbb, 0xb9, 0xb8, 0xb6, 0xb4, 0xb1, 0xaf, 0xac, 0xae, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xae, 0xa3, 0xa5, 0xa8, 0xaa, 0xad, 0xaf, 0xb2, 0xb3, 0xb6, 0xb8, 0xb9, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xc0, 0xc0, 0xbe, 0xbd, 0xbc, 0xbb, 0xb9, 0xb8, 0xb6, 0xb4, 0xb1, 0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb6, 0x9e, 0xa1, 0xa3, 0xa6, 0xa8, 0xaa, 0xad, 0xb0, 0xb2, 0xb3, 0xbb, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xcb, 0xc2, 0xc1, 0xbf, 0xbe, 0xbe, 0xbc, 0xba, 0xb9, 0xb8, 0xb6, 0xc4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x9c, 0x9c, 0x9e, 0xa1, 0xa3, 0xa6, 0xa8, 0xab, 0xad, 0xb0, 0xca, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd2, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0, 0xbe, 0xbd, 0xbc, 0xba, 0xbd, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa6, 0x9a, 0x99, 0x9c, 0x9f, 0xa1, 0xa4, 0xa6, 0xa8, 0xbd, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0xd1, 0xc4, 0xc4, 0xc3, 0xc2, 0xc0, 0xc0, 0xbe, 0xc0, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xa3, 0x9a, 0x9a, 0x9c, 0xa1, 0xa9, 0xb9, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xcb, 0xc9, 0xc6, 0xc4, 0xc2, 0xc4, 0xcb, 0xb2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x90, 0xb4, 0xb6, 0xb9, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xd1, 0xd5, 0xd6, 0xb6, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x19, 0x26, 0x36, 0x3b, 0x38, 0x2a, 0x2b, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x41, 0x94, 0x95, 0x64, 0x36, 0x1e, 0x15, 0x2c, 0x76, 0xad, 0xad, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x85, 0x31, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x61, 0x00, 0x2e, 0xb2, 0x97, 0x00, 0x00, 0x00, 0x0b, 0x5d, 0xb2, 0xb6, 0xab, 0xa6, 0xa4, 0xaa, 0xb2, 0xbe, 0xbf, 0xb1, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x72, 0x7d, 0x5e, 0x4e, 0x49, 0x55, 0x86, 0x8f, 0x41, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x95, 0x00, 0x00, 0x00, 0x3e, 0xb5, 0x81, 0x80, 0xb1, 0xab, 0x9d, 0x95, 0x8f, 0x8e, 0x8d, 0x8c, 0x8d, 0x90, 0x93, 0x97, 0x9f, 0xa8, 0xbb, 0xaf, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x8e, 0x60, 0x1a, 0x4e, 0x86, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x63, 0x16, 0x00, 0x00, 0x00, 0x02, 0x5e, 0x52, 0x5e, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xae, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x73, 0x47, 0x98, 0x96, 0x96, 0x96, 0x94, 0x94, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8e, 0x92, 0x95, 0x97, 0x99, 0x9d, 0xb3, 0xc2, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb0, 0x33, 0x00, 0x00, 0x0f, 0xad, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x78, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xb0, 0x39, 0x00, 0x00, 0x00, 0x42, 0xd1, 0x59, 0x4c, 0x78, 0x9d, 0x9a, 0x98, 0x97, 0x95, 0x95, 0x93, 0x92, 0x90, 0x8f, 0x8e, 0x8d, 0x8f, 0x92, 0x95, 0x98, 0x9b, 0x9b, 0xba, 0x9f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x30, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb4, 0x37, 0x00, 0x00, 0x00, 0x15, 0xac, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x8b, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6f, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x7d, 0x00, 0x00, 0x01, 0x92, 0xc7, 0xac, 0x5f, 0x4c, 0x67, 0xa3, 0x9e, 0x9b, 0x99, 0x98, 0x98, 0x96, 0x95, 0x93, 0x91, 0x90, 0x8f, 0x8d, 0x8d, 0x8f, 0x92, 0x95, 0x99, 0x9c, 0xa0, 0xce, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb4, 0xb3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xb4, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x9c, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x9c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xb4, 0x13, 0x00, 0x00, 0xce, 0xc2, 0xb5, 0xb5, 0x51, 0x4c, 0x67, 0xa9, 0xa2, 0xa0, 0x9d, 0x9b, 0x99, 0x99, 0x97, 0x96, 0x95, 0x93, 0x92, 0x90, 0x8f, 0x8d, 0x8e, 0x90, 0x93, 0x96, 0x99, 0x9b, 0xc8, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x50, 0x00, 0x00, 0x00, 0x00, 0x95, 0xb3, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x83, 0xb3, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x47, 0x00, 0x00, 0x56,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x22, 0xb3, 0x5e, 0x00, 0x00, 0xc3, 0xc7, 0xbd, 0xbb, 0xb5, 0x48, 0x4c, 0x7c, 0xad, 0xa8, 0xa5, 0xa2, 0x9f, 0x9d, 0x9b, 0x99, 0x99, 0x97, 0x95, 0x95, 0x93, 0x92, 0x90, 0x8e, 0x8d, 0x8e, 0x91, 0x93, 0x96, 0x9a, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xb1, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb4, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x53, 0xb3, 0xb4, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x74, 0x0b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x85, 0x00, 0x00, 0x00, 0x07, 0xb0, 0xb3, 0x0a, 0x00, 0x8d, 0xd1, 0xc5, 0xc2, 0xbf, 0xa9, 0x4a, 0x4b, 0xa0, 0xb1, 0xae, 0xaa, 0xa8, 0xa5, 0xa1, 0x9f, 0x9c, 0x9b, 0x99, 0x98, 0x96, 0x95, 0x94, 0x93, 0x91, 0x8f, 0x8e, 0x8d, 0x8e, 0x91, 0x94, 0x99, 0xbd, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x14, 0xab, 0xb3, 0x42, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xb4, 0x4c, 0x00, 0x00, 0x00, 0x2f, 0xb3, 0xb3, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x52, 0x00, 0x62, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x73, 0x16, 0x00, 0x00, 0x00, 0x00, 0x25, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb4, 0x5b, 0x00, 0x00, 0x00, 0x6a, 0xb3, 0x61, 0x00, 0x53, 0xdf, 0xcb, 0xc9, 0xc6, 0xc6, 0x85, 0x4c, 0x51, 0xba, 0xb7, 0xb4, 0xb1, 0xac, 0xaa, 0xa7, 0xa4, 0xa1, 0x9f, 0x9c, 0x9a, 0x98, 0x98, 0x96, 0x95, 0x94, 0x92, 0x91, 0x8f, 0x8f, 0x8e, 0x90, 0x91, 0xa7, 0x5c, 0x97, 0x7a, 0x00, 0x00, 0x00, 0x07, 0x7f, 0xb2, 0xad, 0x01, 0x00, 0x00, 0x00, 0x79, 0xb4, 0x95, 0x00, 0x00, 0x00, 0x14, 0xa2, 0xb3, 0xb2, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x16, 0x6a, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x19, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xb4, 0x21, 0x00, 0x00, 0x28, 0xb4, 0xad, 0x02, 0x00, 0xe0, 0xd0, 0xd0, 0xcd, 0xcb, 0xc8, 0x46, 0x4c, 0xaf, 0xbf, 0xbd, 0xba, 0xb6, 0xb3, 0xb1, 0xaf, 0xad, 0xab, 0xa7, 0xa4, 0xa0, 0x9c, 0x9a, 0x99, 0x97, 0x96, 0x95, 0x93, 0x8f, 0x72, 0x5a, 0x63, 0x8e, 0x8b, 0x41, 0xac, 0x00, 0x00, 0x00, 0x00, 0x60, 0x6e, 0xb3, 0x23, 0x00, 0x00, 0x00, 0x14, 0xb2, 0xb3, 0x25, 0x00, 0x00, 0x00, 0x73, 0x48, 0xb3, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xa6, 0x46, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xa8, 0x00, 0x00, 0x00, 0x96, 0xb3, 0x71, 0x00, 0xb0, 0xdd, 0xd6, 0xd4, 0xd2, 0xd0, 0x83, 0x4a, 0x73, 0xc6, 0xc3, 0xc1, 0xbf, 0xbc, 0xca, 0xdb, 0x88, 0x64, 0x21, 0x52, 0x69, 0xce, 0xbe, 0x9d, 0x9c, 0x9a, 0x98, 0x98, 0x72, 0x52, 0x8d, 0x92, 0x83, 0x81, 0x57, 0x4b, 0x3a, 0x00, 0x00, 0x00, 0x69, 0x41, 0xb4, 0xa4, 0x00, 0x00, 0x00, 0x03, 0xb2, 0xb3, 0x6f, 0x00, 0x00, 0x00, 0x7f, 0x04, 0x6e, 0xb3, 0x55, 0x00, 0x00, 0x00, 0x00, 0x35, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x99, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x7d, 0x00, 0x00, 0x53, 0xb4, 0xae, 0x00, 0x00, 0xeb, 0xdc, 0xda, 0xd8, 0xd6, 0xb9, 0x49, 0x69, 0xce, 0xca, 0xc8, 0xc5, 0xc5, 0xdf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0xc7, 0xa5, 0x9e, 0x96, 0x55, 0x5c, 0x97, 0x96, 0x95, 0x86, 0x7f, 0x4c, 0x4a, 0xb3, 0x00, 0x00, 0x2e, 0x28, 0xaf, 0xb1, 0x0d, 0x00, 0x00, 0x00, 0x6a, 0xb3, 0xb3, 0x0e, 0x00, 0x00, 0x2c, 0x1d, 0x00, 0x6e, 0xb3, 0x0e, 0x00, 0x00, 0x00, 0x28, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x09, 0x83, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xb3, 0x1a, 0x00, 0x00, 0xa9, 0xb3, 0x72, 0x00, 0xaf, 0xe5, 0xe1, 0xdf, 0xdc, 0xd3, 0x4e, 0x74, 0xd4, 0xd0, 0xcf, 0xcc, 0xca, 0xd3, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x35, 0x73, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x93, 0x4e, 0x5b, 0x9e, 0x9a, 0x98, 0x98, 0x74, 0x58, 0x4c, 0x77, 0xa5, 0x33, 0x05, 0x52, 0x73, 0xb4, 0x7e, 0x00, 0x00, 0x00, 0x35, 0xb4, 0xb3, 0x58, 0x00, 0x00, 0x10, 0x56, 0x00, 0x00, 0x53, 0xb2, 0x00, 0x00, 0x00, 0x4b, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x4b, 0x04, 0x00, 0x00, 0x00, 0x1b, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 0x59, 0xb3, 0xb2, 0x09, 0x08, 0xed, 0xe3, 0xe4, 0xe5, 0xc7, 0x47, 0x8e, 0xde, 0xd7, 0xd5, 0xd3, 0xd0, 0xe2, 0x1c, 0x25, 0x31, 0x01, 0x00, 0x96, 0xb4, 0x17, 0x00, 0x00, 0x00, 0x00, 0x33, 0x54, 0x53, 0xa5, 0xa0, 0x9d, 0x9b, 0x9a, 0x4b, 0x4c, 0x4d, 0x93, 0x98, 0x99, 0x8a, 0x09, 0xb1, 0xb1, 0x01, 0x00, 0x00, 0x0d, 0x76, 0xb4, 0xb2, 0x06, 0x00, 0x05, 0x73, 0x00, 0x00, 0x00, 0x1b, 0xb1, 0x4f, 0x2f, 0x77, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x5d, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xb3, 0x1d, 0x00, 0x06, 0xb1, 0xb3, 0x6a, 0x00, 0x40, 0xde, 0xde, 0xd8, 0x95, 0x5e, 0xdd, 0xe1, 0xde, 0xdc, 0xd9, 0xd7, 0xd8, 0xa7, 0x92, 0x38, 0x43, 0x37, 0x45, 0xb4, 0x92, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xb3, 0x7e, 0x98, 0xa8, 0xa5, 0xa2, 0x9f, 0x7c, 0x4b, 0x4c, 0x82, 0x97, 0x94, 0xa8, 0x0b, 0x7d, 0xb4, 0x5e, 0x00, 0x00, 0x00, 0x83, 0x19, 0xb3, 0x71, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1b, 0x00, 0x00, 0x00, 0x2b, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xb3, 0x58, 0x00, 0x00, 0x46, 0xb3, 0xb4, 0x16, 0x00, 0x90, 0x92, 0x84, 0xa8, 0xdf, 0xe3, 0xe4, 0xe4, 0xe2, 0xe0, 0xde, 0xdc, 0x5f, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x9b, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xb3, 0xb3, 0x58, 0xca, 0xac, 0xaa, 0xa7, 0xa9, 0x4f, 0x4c, 0x4e, 0x99, 0x99, 0x8f, 0x85, 0x00, 0xa9, 0xae, 0x00, 0x00, 0x00, 0x97, 0x0f, 0x1c, 0xb3, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xab, 0xac, 0x01, 0x00, 0x04, 0xb2, 0xb3, 0x6d, 0x00, 0x00, 0xea, 0xdd, 0xde, 0xdf, 0xdf, 0xe0, 0xe1, 0xe3, 0xe4, 0xe5, 0xc9, 0x51, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x95, 0xb4, 0x6d, 0x00, 0x00, 0x00, 0x02, 0xae, 0xb3, 0xb3, 0x02, 0xa5, 0xb2, 0xb0, 0xad, 0x70, 0x55, 0x4a, 0x8a, 0x9f, 0xa1, 0x71, 0xa6, 0x22, 0xaf, 0x4d, 0x00, 0x00, 0x77, 0x19, 0x00, 0x00, 0x9e, 0x87, 0x70, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0xb0, 0x0a, 0x00, 0x00, 0x3e, 0xb3, 0xb4, 0x11, 0x00, 0x1f, 0xe5, 0xd9, 0xda, 0xdc, 0xdd, 0xdf, 0xdf, 0xe1, 0xe4, 0xbb, 0x49, 0x83, 0x6d, 0x00, 0x00, 0x00, 0x4f, 0xb4, 0xae, 0x00, 0x00, 0x00, 0x00, 0x79, 0xb4, 0xb3, 0x5a, 0x00, 0x72, 0xba, 0xb7, 0xa5, 0x7a, 0x48, 0x57, 0xa9, 0xa7, 0x73, 0x9e, 0xa2, 0x5e, 0xb1, 0x23, 0x00, 0x6c, 0x27, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x19, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xb3, 0x2e, 0x00, 0x00, 0x00, 0xa5, 0xb3, 0x80, 0x00, 0x00, 0x3a, 0xde, 0xd8, 0xd9, 0xd9, 0xdb, 0xdc, 0xdd, 0xdf, 0xbc, 0x46, 0x56, 0xe6, 0x74, 0x51, 0x51, 0x50, 0x8d, 0x8e, 0x7f, 0x4e, 0x4f, 0x4f, 0x52, 0x73, 0x90, 0x90, 0x4e, 0x4c, 0x91, 0xc1, 0xbc, 0x6e, 0x64, 0x48, 0x92, 0xad, 0x7c, 0x9f, 0xa3, 0xa5, 0x6b, 0x95, 0x77, 0x77, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3f, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xb3, 0x37, 0x00, 0x00, 0x00, 0x42, 0xb4, 0xb0, 0x02, 0x00, 0x00, 0x47, 0xd3, 0xd4, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xd0, 0x4a, 0x49, 0xc5, 0xe1, 0xe2, 0xe3, 0xe4, 0xc1, 0x4c, 0x4c, 0xdf, 0xd9, 0xd7, 0xcd, 0xae, 0xaa, 0x48, 0x5e, 0xca, 0xc6, 0xc3, 0xc4, 0x73, 0xba, 0x4a, 0x61, 0xbb, 0x8e, 0xa8, 0xab, 0xa9, 0xa9, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3d, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xb2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x98, 0xb3, 0x72, 0x00, 0x00, 0x00, 0x68, 0xca, 0xce, 0xd1, 0xd5, 0xd7, 0xd8, 0xdb, 0x59, 0x4c, 0x6e, 0xde, 0xdf, 0xe0, 0xe1, 0xdf, 0x48, 0x4c, 0xb3, 0xe1, 0xde, 0xda, 0x81, 0xda, 0xac, 0x46, 0x9b, 0xce, 0xcc, 0xcd, 0x89, 0xc4, 0x6a, 0x48, 0xa1, 0x89, 0xb4, 0xb5, 0xb2, 0xaf, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x05, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x94, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xb3, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x8b, 0xc4, 0xc9, 0xcb, 0xce, 0xd2, 0xd5, 0x6d, 0x4b, 0x44, 0xc7, 0xdb, 0xdc, 0xde, 0xe3, 0x94, 0x4c, 0x47, 0xe1, 0xe4, 0xe5, 0x7a, 0xdc, 0xdc, 0xc1, 0x42, 0xbe, 0xd3, 0xd8, 0x7c, 0xc0, 0xc7, 0x4f, 0x6e, 0x7d, 0xb9, 0xbe, 0xbb, 0xb8, 0xb4, 0xb2, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x72, 0x1e, 0x00, 0x00, 0x00, 0x5b, 0x95, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xb4, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x8e, 0xbe, 0xc2, 0xc5, 0xc9, 0xcc, 0xcc, 0x50, 0x4c, 0x6d, 0xde, 0xd9, 0xda, 0xdb, 0xb4, 0x5e, 0x4b, 0xa8, 0xe3, 0xe8, 0xa5, 0xdb, 0xe1, 0xdf, 0xe2, 0x61, 0x71, 0x98, 0x81, 0xc5, 0xd1, 0x9c, 0x4b, 0x7f, 0xc3, 0xc4, 0xc2, 0xbf, 0xbd, 0xbb, 0xb8, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x63, 0x67, 0x7b, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xb3, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xb8, 0xbc, 0xbf, 0xc3, 0xc6, 0xc7, 0x50, 0x4a, 0xa3, 0xd5, 0xd7, 0xd9, 0xcf, 0x9a, 0x87, 0x50, 0xdb, 0xe3, 0xb1, 0xbf, 0xe2, 0xe4, 0xe4, 0xe2, 0xdd, 0xb0, 0xc2, 0xde, 0xd8, 0xce, 0x4c, 0x4b, 0xcb, 0xcb, 0xc9, 0xc6, 0xc4, 0xc1, 0xbf, 0xbd, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xb3, 0xb1, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xb1, 0xb6, 0xba, 0xbc, 0xc0, 0xc0, 0x4f, 0x45, 0xc2, 0xd0, 0xd4, 0xd5, 0x87, 0xe2, 0x94, 0x57, 0xdc, 0xac, 0xb9, 0xdf, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe1, 0xe0, 0xde, 0xc8, 0x70, 0x4b, 0xa1, 0xd3, 0xcf, 0xcd, 0xcb, 0xc9, 0xc6, 0xc4, 0xc2, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xb3, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xab, 0xb0, 0xb3, 0xb7, 0xba, 0xbc, 0x50, 0x48, 0xce, 0xca, 0xcc, 0x70, 0xd4, 0xd7, 0xc9, 0x51, 0x5c, 0xd2, 0xdb, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe3, 0xe5, 0xe3, 0xb1, 0xba, 0x77, 0x50, 0xd4, 0xd6, 0xd4, 0xd1, 0xcf, 0xcd, 0xca, 0xc9, 0xc8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xb3, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0xa6, 0xaa, 0xac, 0xb0, 0xb4, 0xb8, 0x6a, 0x45, 0xc6, 0xb8, 0x78, 0xc8, 0xd6, 0xd9, 0xdc, 0xde, 0xe1, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe9, 0x91, 0xd6, 0xd7, 0x3f, 0xac, 0xe3, 0xe2, 0xdf, 0xde, 0xdb, 0xda, 0xd8, 0xd6, 0xd5, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xa8, 0xa2, 0xa6, 0xa9, 0xad, 0xb0, 0xb2, 0x72, 0x72, 0x93, 0xc4, 0xca, 0x4d, 0x25, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x24, 0x95, 0x1e, 0x25, 0x75, 0x91, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x24, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xad, 0x9c, 0xa0, 0xa3, 0xa7, 0xaa, 0xae, 0xb4, 0xb9, 0xb9, 0xbc, 0xbe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x74, 0x00, 0x00, 0x00, 0xb0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xb5, 0x95, 0x99, 0x9c, 0xa0, 0xa3, 0xa7, 0xab, 0xae, 0xb2, 0xb4, 0xb8, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x84, 0x00, 0x00, 0x00, 0x71, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x8e, 0x92, 0x96, 0x9a, 0x9d, 0xa1, 0xa4, 0xa8, 0xab, 0xae, 0xb2, 0xc5, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0xb1, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1a, 0xb1, 0xb2, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x8a, 0x8b, 0x8f, 0x92, 0x96, 0x9a, 0x9d, 0xa1, 0xa4, 0xa8, 0xac, 0xae, 0xd0, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x00, 0x00, 0x8c, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x60, 0xb3, 0xb3, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x9c, 0x85, 0x88, 0x8c, 0x8f, 0x92, 0x97, 0x9b, 0x9e, 0xa2, 0xa5, 0xa9, 0xae, 0xca, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x90, 0x20, 0x00, 0x00, 0x00, 0x14, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x6a, 0xb3, 0xb3, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xac, 0x81, 0x83, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x97, 0x9a, 0x9e, 0xa2, 0xa5, 0xaa, 0xcb, 0x57, 0x00, 0x00, 0x4d, 0x73, 0x00, 0x00, 0x00, 0x01, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x67, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2e, 0xb2, 0xb3, 0x8b, 0x15, 0x1b, 0x34, 0x7a, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x88, 0x7d, 0x81, 0x84, 0x86, 0x89, 0x8d, 0x90, 0x93, 0x98, 0x9b, 0x9f, 0xa3, 0xa4, 0xba, 0xcd, 0x51, 0xa1, 0x05, 0x00, 0x00, 0x00, 0x56, 0x32, 0x00, 0x00, 0x00, 0x12, 0x17, 0x2c, 0x80, 0xd8, 0xe9, 0xe2, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x19, 0x82, 0x97, 0x88, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x77, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x89, 0x8d, 0x91, 0x94, 0x98, 0x9b, 0x9f, 0xa3, 0xa6, 0x7f, 0x6b, 0xd5, 0xd6, 0xd0, 0x89, 0x98, 0xb0, 0xd6, 0xe1, 0xe4, 0xe4, 0xdf, 0xdb, 0xd7, 0xd7, 0xd9, 0xda, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x89, 0x75, 0x79, 0x7b, 0x7e, 0x82, 0x85, 0x88, 0x89, 0x8d, 0x91, 0x94, 0x99, 0x9c, 0xa1, 0x6a, 0x72, 0xaa, 0xaf, 0xa4, 0x7d, 0xbb, 0xbd, 0xbf, 0xc2, 0xc6, 0xc8, 0xcb, 0xce, 0xd2, 0xd5, 0xd7, 0xd8, 0xe9, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x77, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, 0x88, 0x8a, 0x8e, 0x92, 0x95, 0x9a, 0x6c, 0x64, 0xa8, 0x7d, 0x83, 0xb0, 0xb2, 0xb6, 0xb9, 0xbc, 0xbf, 0xc2, 0xc6, 0xc9, 0xcc, 0xcf, 0xd3, 0xd5, 0xe2, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x6f, 0x70, 0x73, 0x76, 0x79, 0x7c, 0x7f, 0x82, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x8f, 0x68, 0x6c, 0x93, 0xa6, 0xa8, 0xac, 0xaf, 0xb2, 0xb6, 0xb9, 0xbc, 0xc0, 0xc2, 0xc6, 0xca, 0xcc, 0xd0, 0xd9, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x8c, 0x6d, 0x6e, 0x71, 0x74, 0x76, 0x7a, 0x7d, 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8f, 0x93, 0x97, 0x9a, 0x9e, 0xa1, 0xa5, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xb9, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xcc, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x89, 0x6c, 0x6b, 0x6e, 0x71, 0x75, 0x77, 0x7a, 0x7d, 0x80, 0x83, 0x85, 0x89, 0x8b, 0x90, 0x93, 0x96, 0x9b, 0x9e, 0xa2, 0xa6, 0xa9, 0xac, 0xb0, 0xb4, 0xb7, 0xba, 0xbd, 0xc0, 0xc4, 0xc6, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x78, 0x77, 0x68, 0x6c, 0x6e, 0x72, 0x75, 0x77, 0x7b, 0x7d, 0x80, 0x83, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x97, 0x9b, 0x9e, 0xa2, 0xa6, 0xa9, 0xad, 0xb0, 0xb4, 0xb7, 0xba, 0xbd, 0xc1, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x82, 0x6f, 0x68, 0x6c, 0x6f, 0x73, 0x75, 0x78, 0x7a, 0x7e, 0x80, 0x84, 0x86, 0x8a, 0x8c, 0x90, 0x94, 0x98, 0x9c, 0x9f, 0xa3, 0xa6, 0xaa, 0xad, 0xb1, 0xb5, 0xb7, 0xba, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4b, 0x7d, 0x73, 0x69, 0x6b, 0x70, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x91, 0x94, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa9, 0xb1, 0xbd, 0xc4, 0x85, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x70, 0x7a, 0x72, 0x71, 0x71, 0x73, 0x75, 0x78, 0x7c, 0x7e, 0x81, 0x84, 0x86, 0x89, 0x8d, 0x93, 0x99, 0x9e, 0xa6, 0xae, 0xa5, 0x8c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x50, 0x7f, 0x85, 0x88, 0x87, 0x86, 0x89, 0x8d, 0x90, 0x97, 0x9e, 0x9d, 0x9b, 0x78, 0x4d, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "../../../options.h"
|
||||
#if DSP_MODEL==DSP_ILI9225
|
||||
#ifndef YOFONT10X14_H
|
||||
#define YOFONT10X14_H
|
||||
|
||||
@@ -274,5 +272,3 @@ const unsigned char yofont10x14[] PROGMEM = {
|
||||
0x0A, 0xC0, 0x30, 0xC0, 0x30, 0x30, 0x0F, 0x30, 0x0F, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0xF0, 0x3F, 0xF0, 0x3F
|
||||
};
|
||||
#endif // YOFONT10X14_H
|
||||
|
||||
#endif //DSP_ILI9225
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "../../../options.h"
|
||||
#if DSP_MODEL==DSP_ILI9225
|
||||
#ifndef YOFONTFONT5X7_H
|
||||
#define YOFONTFONT5X7_H
|
||||
|
||||
@@ -272,4 +270,3 @@ const unsigned char yofont5x7[] PROGMEM = {
|
||||
0x05, 0x48, 0x34, 0x14, 0x14, 0x7C
|
||||
};
|
||||
#endif // YOFONTFONT5X7_H
|
||||
#endif //DSP_ILI9225
|
||||
|
||||
@@ -1,41 +1,19 @@
|
||||
#include "../../options.h"
|
||||
#include "../core/options.h"
|
||||
|
||||
#if NEXTION_RX!=255 && NEXTION_TX!=255
|
||||
#include "nextion.h"
|
||||
#include "../../config.h"
|
||||
#include "../core/config.h"
|
||||
|
||||
#include "../../player.h"
|
||||
#include "../../controls.h"
|
||||
#include "../../netserver.h"
|
||||
#include "../../network.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/controls.h"
|
||||
#include "../core/netserver.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef CORE_STACK_SIZE
|
||||
#define CORE_STACK_SIZE 1024*3
|
||||
#define CORE_STACK_SIZE 1024*3
|
||||
#endif
|
||||
|
||||
HardwareSerial hSerial(1); // use UART1
|
||||
Ticker weatherticker;
|
||||
//char weather[254] = { 0 };
|
||||
//bool weatherRequest = false;
|
||||
|
||||
|
||||
const char *ndow[7] = {"воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"};
|
||||
const char *nmnths[12] = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"};
|
||||
|
||||
#ifdef DUMMYDISPLAY
|
||||
void ticks() {
|
||||
network.timeinfo.tm_sec ++;
|
||||
mktime(&network.timeinfo);
|
||||
nextion.putRequest({CLOCK,0});
|
||||
if(nextion.mode==TIMEZONE) nextion.localTime(network.timeinfo);
|
||||
if(nextion.mode==INFO) nextion.rssi();
|
||||
if(nextion.dt){
|
||||
int rssi = WiFi.RSSI();
|
||||
netserver.setRSSI(rssi);
|
||||
}
|
||||
nextion.dt=!nextion.dt;
|
||||
}
|
||||
#endif
|
||||
|
||||
Nextion::Nextion() {
|
||||
|
||||
@@ -44,24 +22,12 @@ Nextion::Nextion() {
|
||||
void nextionCore0( void * pvParameters ){
|
||||
delay(500);
|
||||
while(true){
|
||||
// if(displayQueue==NULL) break;
|
||||
nextion.loop();
|
||||
vTaskDelay(5);
|
||||
}
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
|
||||
void Nextion::createCore0Task(){
|
||||
xTaskCreatePinnedToCore(
|
||||
nextionCore0, /* Task function. */
|
||||
"TaskCore0", /* name of task. */
|
||||
CORE_STACK_SIZE, /* Stack size of task */
|
||||
NULL, /* parameter of the task */
|
||||
4, /* no one flies higher than the Toruk */
|
||||
&_TaskCore0, /* Task handle to keep track of created task */
|
||||
!xPortGetCoreID()); /* pin task to core 0 */
|
||||
}
|
||||
|
||||
void Nextion::begin(bool dummy) {
|
||||
_dummyDisplay=dummy;
|
||||
hSerial.begin(NEXTION_BAUD, SERIAL_8N1, NEXTION_RX, NEXTION_TX);
|
||||
@@ -80,9 +46,10 @@ void Nextion::begin(bool dummy) {
|
||||
putcmd("");
|
||||
putcmd("bkcmd=0");
|
||||
// putcmd("page boot");
|
||||
if(dummy) {
|
||||
|
||||
_displayQueue = xQueueCreate( 5, sizeof( requestParams_t ) );
|
||||
createCore0Task();
|
||||
if(dummy) {
|
||||
xTaskCreatePinnedToCore(nextionCore0, "TaskCore0", CORE_STACK_SIZE, NULL, 4, &_TaskCore0, !xPortGetCoreID());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,30 +59,20 @@ void Nextion::start(){
|
||||
return;
|
||||
}
|
||||
#ifdef DUMMYDISPLAY
|
||||
if(_dummyDisplay) _timer.attach_ms(1000, ticks);
|
||||
display.mode = PLAYER;
|
||||
config.setTitle("[READY]");
|
||||
display.mode(PLAYER);
|
||||
config.setTitle(const_PlReady);
|
||||
#endif
|
||||
mode = PLAYER;
|
||||
putcmd("page player");
|
||||
delay(100);
|
||||
#ifdef DUMMYDISPLAY
|
||||
newNameset(config.station.name);
|
||||
newTitle(config.station.title);
|
||||
#endif
|
||||
setVol(config.store.volume, mode == VOL);
|
||||
}
|
||||
|
||||
void Nextion::apScreen() {
|
||||
putcmd("apscreenlock=1");
|
||||
putcmd("page settings_wifi");
|
||||
//char cmd[20];
|
||||
/*for(int i=0;i<5;i++){
|
||||
snprintf(cmd, sizeof(cmd)-1, "vis b%d,%d", i, 0);
|
||||
putcmd(cmd);
|
||||
}*/
|
||||
//putcmd("vis btnBack,0");
|
||||
|
||||
}
|
||||
|
||||
void Nextion::putRequest(requestParams_t request){
|
||||
@@ -128,20 +85,14 @@ void Nextion::processQueue(){
|
||||
requestParams_t request;
|
||||
if(xQueueReceive(_displayQueue, &request, 20)){
|
||||
switch (request.type){
|
||||
case NEWMODE: {
|
||||
swichMode((displayMode_e)request.payload);
|
||||
break;
|
||||
}
|
||||
case CLOCK: {
|
||||
printClock(network.timeinfo);
|
||||
break;
|
||||
}
|
||||
case NEWTITLE: {
|
||||
newTitle(config.station.title);
|
||||
break;
|
||||
}
|
||||
case RETURNTITLE: {
|
||||
//returnTile();
|
||||
case NEWMODE: swichMode((displayMode_e)request.payload); break;
|
||||
case CLOCK: printClock(network.timeinfo); break;
|
||||
case DSPRSSI: rssi(); break;
|
||||
case NEWTITLE: newTitle(config.station.title); break;
|
||||
case BOOTSTRING: {
|
||||
char buf[50];
|
||||
snprintf(buf, 50, bootstrFmt, config.ssids[request.payload].ssid);
|
||||
bootString(buf);
|
||||
break;
|
||||
}
|
||||
case NEWSTATION: {
|
||||
@@ -150,18 +101,9 @@ void Nextion::processQueue(){
|
||||
bitratePic(ICON_NA);
|
||||
break;
|
||||
}
|
||||
case NEXTSTATION: {
|
||||
drawNextStationNum((displayMode_e)request.payload);
|
||||
break;
|
||||
}
|
||||
case DRAWPLAYLIST: {
|
||||
int p = request.payload ? display.currentPlItem + 1 : display.currentPlItem - 1;
|
||||
if (p < 1) p = config.store.countStation;
|
||||
if (p > config.store.countStation) p = 1;
|
||||
display.currentPlItem = p;
|
||||
drawPlaylist(display.currentPlItem);
|
||||
break;
|
||||
}
|
||||
case SHOWWEATHER: weatherVisible(strlen(config.store.weatherkey)>0 && config.store.showweather); break;
|
||||
case NEXTSTATION: drawNextStationNum(request.payload); break;
|
||||
case DRAWPLAYLIST: drawPlaylist(request.payload); break;
|
||||
case DRAWVOL: {
|
||||
if(!_volInside){
|
||||
setVol(config.store.volume, mode == VOL);
|
||||
@@ -169,36 +111,17 @@ void Nextion::processQueue(){
|
||||
_volInside=false;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
switch (mode) {
|
||||
case PLAYER: {
|
||||
//drawPlayer();
|
||||
break;
|
||||
}
|
||||
case INFO:
|
||||
case TIMEZONE: {
|
||||
//sendInfo();
|
||||
break;
|
||||
}
|
||||
case VOL: {
|
||||
if (millis() - _volDelay > 3000) {
|
||||
_volDelay = millis();
|
||||
swichMode(PLAYER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NUMBERS: {
|
||||
//meta.loop();
|
||||
break;
|
||||
}
|
||||
case STATIONS: {
|
||||
//plCurrent.loop();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
#ifdef DUMMYDISPLAY
|
||||
if(mode==VOL || mode==STATIONS || mode==NUMBERS ){
|
||||
if (millis() - _volDelay > (mode==VOL?3000:30000)) {
|
||||
_volDelay = millis();
|
||||
swichMode(PLAYER);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Nextion::loop() {
|
||||
@@ -230,14 +153,14 @@ void Nextion::loop() {
|
||||
rxbuf[rx_pos] = '\0';
|
||||
rx_pos = 0;
|
||||
if (sscanf(rxbuf, "page=%s", scanBuf) == 1){
|
||||
if(strcmp(scanBuf, "player") == 0) display.putRequest({NEWMODE, PLAYER});
|
||||
if(strcmp(scanBuf, "playlist") == 0) display.putRequest({NEWMODE, STATIONS});
|
||||
if(strcmp(scanBuf, "player") == 0) display.putRequest(NEWMODE, PLAYER);
|
||||
if(strcmp(scanBuf, "playlist") == 0) display.putRequest(NEWMODE, STATIONS);
|
||||
if(strcmp(scanBuf, "info") == 0) {
|
||||
putcmd("yoversion.txt", VERSION);
|
||||
putcmd("espcore.txt", _espcoreversion);
|
||||
putcmd("ipaddr.txt", WiFi.localIP().toString().c_str());
|
||||
putcmd("ssid.txt", WiFi.SSID().c_str());
|
||||
display.putRequest({NEWMODE, INFO});
|
||||
display.putRequest(NEWMODE, INFO);
|
||||
}
|
||||
if(strcmp(scanBuf, "eq") == 0) {
|
||||
putcmd("t4.txt", config.store.balance, true);
|
||||
@@ -248,7 +171,7 @@ void Nextion::loop() {
|
||||
putcmd("h2.val", config.store.middle+16);
|
||||
putcmd("t7.txt", config.store.bass, true);
|
||||
putcmd("h3.val", config.store.bass+16);
|
||||
display.putRequest({NEWMODE, SETTINGS});
|
||||
display.putRequest(NEWMODE, SETTINGS);
|
||||
}
|
||||
if(strcmp(scanBuf, "wifi") == 0) {
|
||||
if(mode != WIFI){
|
||||
@@ -260,7 +183,7 @@ void Nextion::loop() {
|
||||
snprintf(cell, sizeof(cell) - 1, "t%d.txt", i*2+1);
|
||||
putcmd(cell, config.ssids[i].password);
|
||||
}
|
||||
display.putRequest({NEWMODE, WIFI});
|
||||
display.putRequest(NEWMODE, WIFI);
|
||||
}
|
||||
}
|
||||
if(strcmp(scanBuf, "time") == 0) {
|
||||
@@ -268,25 +191,31 @@ void Nextion::loop() {
|
||||
putcmd("tzHour.val", config.store.tzHour);
|
||||
putcmdf("tzMinText.txt=\"%02d\"", config.store.tzMin);
|
||||
putcmd("tzMin.val", config.store.tzMin);
|
||||
display.putRequest({NEWMODE, TIMEZONE});
|
||||
display.putRequest(NEWMODE, TIMEZONE);
|
||||
}
|
||||
if(strcmp(scanBuf, "sys") == 0) {
|
||||
putcmd("smartstart.val", config.store.smartstart==2?0:1);
|
||||
putcmd("audioinfo.val", config.store.audioinfo);
|
||||
display.putRequest({NEWMODE, SETTINGS});
|
||||
display.putRequest(NEWMODE, SETTINGS);
|
||||
}
|
||||
}
|
||||
if (sscanf(rxbuf, "ctrls=%s", scanBuf) == 1){
|
||||
if(strcmp(scanBuf, "up") == 0) {
|
||||
display.resetQueue();
|
||||
display.putRequest({DRAWPLAYLIST, false});
|
||||
int p = display.currentPlItem - 1;
|
||||
if (p < 1) p = config.store.countStation;
|
||||
display.currentPlItem = p;
|
||||
display.putRequest(DRAWPLAYLIST, p);
|
||||
}
|
||||
if(strcmp(scanBuf, "dn") == 0) {
|
||||
display.resetQueue();
|
||||
display.putRequest({DRAWPLAYLIST, true});
|
||||
int p = display.currentPlItem + 1;
|
||||
if (p > config.store.countStation) p = 1;
|
||||
display.currentPlItem = p;
|
||||
display.putRequest(DRAWPLAYLIST, p);
|
||||
}
|
||||
if(strcmp(scanBuf, "go") == 0) {
|
||||
display.putRequest({NEWMODE, PLAYER});
|
||||
display.putRequest(NEWMODE, PLAYER);
|
||||
player.request.station=display.currentPlItem;
|
||||
}
|
||||
if(strcmp(scanBuf, "toggle") == 0) {
|
||||
@@ -320,23 +249,21 @@ void Nextion::loop() {
|
||||
}
|
||||
if (sscanf(rxbuf, "tzhour=%d", &scanDigit) == 1){
|
||||
config.setTimezone((int8_t)scanDigit, config.store.tzMin);
|
||||
//configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), SNTP_SERVER);
|
||||
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);
|
||||
}else if(strlen(config.store.sntp1)>0){
|
||||
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1);
|
||||
}
|
||||
network.requestTimeSync(true);
|
||||
network.forceTimeSync = true;
|
||||
}
|
||||
if (sscanf(rxbuf, "tzmin=%d", &scanDigit) == 1){
|
||||
config.setTimezone(config.store.tzHour, (int8_t)scanDigit);
|
||||
//configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), SNTP_SERVER);
|
||||
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);
|
||||
}else if(strlen(config.store.sntp1)>0){
|
||||
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1);
|
||||
}
|
||||
network.requestTimeSync(true);
|
||||
network.forceTimeSync = true;
|
||||
}
|
||||
if (sscanf(rxbuf, "audioinfo=%d", &scanDigit) == 1){
|
||||
config.store.audioinfo = scanDigit;
|
||||
@@ -411,7 +338,7 @@ void Nextion::bitrate(int bpm){
|
||||
if(bpm>0){
|
||||
putcmd("player.bitrate.txt", bpm, true);
|
||||
}else{
|
||||
putcmd("player.bitrate.txt=\"und\"");
|
||||
putcmd("player.bitrate.txt=\" \"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,6 +361,13 @@ void Nextion::bitratePic(uint8_t pic){
|
||||
putcmd("player.bitrate.pic", pic);
|
||||
}
|
||||
|
||||
void Nextion::audioinfo(const char* info){
|
||||
if (strstr(info, "format is aac") != NULL) bitratePic(ICON_AAC);
|
||||
if (strstr(info, "format is flac") != NULL) bitratePic(ICON_FLAC);
|
||||
if (strstr(info, "format is mp3") != NULL) bitratePic(ICON_MP3);
|
||||
if (strstr(info, "format is wav") != NULL) bitratePic(ICON_WAV);
|
||||
}
|
||||
|
||||
void Nextion::bootString(const char* bs) {
|
||||
char buf[50] = { 0 };
|
||||
strlcpy(buf, bs, 50);
|
||||
@@ -449,10 +383,7 @@ void Nextion::newNameset(const char* meta){
|
||||
void Nextion::setVol(uint8_t vol, bool dialog){
|
||||
if(dialog){
|
||||
putcmd("dialog.text.txt", vol, true);
|
||||
}/*else{
|
||||
putcmd("player.volText.txt", vol, true);
|
||||
putcmd("player.volumeSlider.val", vol);
|
||||
}*/
|
||||
}
|
||||
putcmd("player.volText.txt", vol, true);
|
||||
putcmd("player.volumeSlider.val", vol);
|
||||
}
|
||||
@@ -480,12 +411,14 @@ void Nextion::newTitle(const char* title){
|
||||
}
|
||||
|
||||
void Nextion::printClock(struct tm timeinfo){
|
||||
char timeStringBuff[70] = { 0 };
|
||||
char timeStringBuff[100] = { 0 };
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "player.clock.txt=\"%H:%M\"", &timeinfo);
|
||||
putcmd(timeStringBuff);
|
||||
putcmdf("player.secText.txt=\"%02d\"", timeinfo.tm_sec);
|
||||
snprintf(timeStringBuff, sizeof(timeStringBuff), "player.dateText.txt=\"%s, %d %s %d\"", ndow[timeinfo.tm_wday], timeinfo.tm_mday, nmnths[timeinfo.tm_mon], timeinfo.tm_year+1900);
|
||||
snprintf(timeStringBuff, sizeof(timeStringBuff), "player.dateText.txt=\"%s, %d %s %d\"", dowf[timeinfo.tm_wday], timeinfo.tm_mday, mnths[timeinfo.tm_mon], timeinfo.tm_year+1900);
|
||||
putcmd(utf8Rus(timeStringBuff, false));
|
||||
if(mode==TIMEZONE) localTime(network.timeinfo);
|
||||
if(mode==INFO) rssi();
|
||||
}
|
||||
|
||||
void Nextion::localTime(struct tm timeinfo){
|
||||
@@ -505,6 +438,7 @@ void Nextion::drawPlaylist(uint16_t currentPlItem){
|
||||
snprintf(cmd, sizeof(cmd) - 1, "t%d.txt=\"%s\"", i, nextion.utf8Rus(plMenu[i], true));
|
||||
putcmd(cmd);
|
||||
}
|
||||
_volDelay = millis();
|
||||
}
|
||||
|
||||
void Nextion::drawNextStationNum(uint16_t num) {//dialog
|
||||
@@ -512,10 +446,9 @@ void Nextion::drawNextStationNum(uint16_t num) {//dialog
|
||||
char currentItemText[40] = {0};
|
||||
config.fillPlMenu(plMenu, num, 1, true);
|
||||
strlcpy(currentItemText, plMenu[0], 39);
|
||||
//meta.setText(dsp.utf8Rus(currentItemText, true));
|
||||
putcmd("dialog.title.txt", utf8Rus(currentItemText, true));
|
||||
putcmd("dialog.text.txt", num, true);
|
||||
//dsp.drawNextStationNum(num);
|
||||
_volDelay = millis();
|
||||
}
|
||||
|
||||
void Nextion::swichMode(displayMode_e newmode){
|
||||
@@ -525,12 +458,8 @@ void Nextion::swichMode(displayMode_e newmode){
|
||||
if (newmode == mode) return;
|
||||
mode = newmode;
|
||||
#ifdef DUMMYDISPLAY
|
||||
display.mode = newmode;
|
||||
display.mode(newmode);
|
||||
#endif
|
||||
/* if (newmode != STATIONS) {
|
||||
ip();
|
||||
volume();
|
||||
}*/
|
||||
if (newmode == PLAYER) {
|
||||
putcmd("page player");
|
||||
putcmd("dialog.title.txt", "");
|
||||
@@ -560,158 +489,6 @@ void Nextion::swichMode(displayMode_e newmode){
|
||||
}
|
||||
}
|
||||
|
||||
bool Nextion::getForecast(){
|
||||
WiFiClient client;
|
||||
const char* host = "api.openweathermap.org";
|
||||
if (!client.connect(host, 80)) {
|
||||
Serial.println("## OPENWEATHERMAP ###: connection failed");
|
||||
return false;
|
||||
}
|
||||
char httpget[250] = {0};
|
||||
sprintf(httpget, "GET /data/2.5/weather?lat=%s&lon=%s&units=metric&lang=ru&appid=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", config.store.weatherlat, config.store.weatherlon, config.store.weatherkey, host);
|
||||
client.print(httpget);
|
||||
unsigned long timeout = millis();
|
||||
while (client.available() == 0) {
|
||||
if (millis() - timeout > 2000UL) {
|
||||
Serial.println("## OPENWEATHERMAP ###: client available timeout !");
|
||||
client.stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
timeout = millis();
|
||||
String line = "";
|
||||
if (client.connected()) {
|
||||
while (client.available())
|
||||
{
|
||||
line = client.readStringUntil('\n');
|
||||
if (strstr(line.c_str(), "\"temp\"") != NULL) {
|
||||
client.stop();
|
||||
break;
|
||||
}
|
||||
if ((millis() - timeout) > 500)
|
||||
{
|
||||
client.stop();
|
||||
Serial.println("## OPENWEATHERMAP ###: client read timeout !");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strstr(line.c_str(), "\"temp\"") == NULL) {
|
||||
Serial.println("## OPENWEATHERMAP ###: weather not found !");
|
||||
return false;
|
||||
}
|
||||
char *tmpe;
|
||||
char *tmps;
|
||||
const char* cursor = line.c_str();
|
||||
char desc[120], temp[20], hum[20], press[20], icon[5];
|
||||
|
||||
tmps = strstr(cursor, "\"description\":\"");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;}
|
||||
tmps += 15;
|
||||
tmpe = strstr(tmps, "\",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: description not found !"); return false;}
|
||||
strlcpy(desc, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
|
||||
// "ясно","icon":"01d"}],
|
||||
tmps = strstr(cursor, "\"icon\":\"");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: icon not found !"); return false;}
|
||||
tmps += 8;
|
||||
tmpe = strstr(tmps, "\"}");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: icon not found !"); return false;}
|
||||
strlcpy(icon, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
|
||||
tmps = strstr(cursor, "\"temp\":");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;}
|
||||
tmps += 7;
|
||||
tmpe = strstr(tmps, ",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: temp not found !"); return false;}
|
||||
strlcpy(temp, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
float tempf = atof(temp);
|
||||
tmps = strstr(cursor, "\"pressure\":");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;}
|
||||
tmps += 11;
|
||||
tmpe = strstr(tmps, ",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: pressure not found !"); return false;}
|
||||
strlcpy(press, tmps, tmpe - tmps + 1);
|
||||
cursor = tmpe + 2;
|
||||
int pressi = (float)atoi(press) / 1.333;
|
||||
|
||||
tmps = strstr(cursor, "humidity\":");
|
||||
if (tmps == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;}
|
||||
tmps += 10;
|
||||
tmpe = strstr(tmps, ",\"");
|
||||
if (tmpe == NULL) { Serial.println("## OPENWEATHERMAP ###: humidity not found !"); return false;}
|
||||
strlcpy(hum, tmps, tmpe - tmps + 1);
|
||||
|
||||
if(config.store.audioinfo) Serial.printf("## OPENWEATHERMAP ###: description: %s, temp:%.1f C, pressure:%dmmHg, humidity:%s%%\n", desc, tempf, pressi, hum);
|
||||
|
||||
putcmdf("press_txt.txt=\"%dmm\"", pressi);
|
||||
putcmdf("hum_txt.txt=\"%d%%\"", atoi(hum));
|
||||
char cmd[30];
|
||||
snprintf(cmd, sizeof(cmd)-1,"temp_txt.txt=\"%.1f\"", tempf);
|
||||
putcmd(cmd);
|
||||
int iconofset;
|
||||
if(strstr(icon,"01")!=NULL){
|
||||
iconofset = 0;
|
||||
}else if(strstr(icon,"02")!=NULL){
|
||||
iconofset = 1;
|
||||
}else if(strstr(icon,"03")!=NULL){
|
||||
iconofset = 2;
|
||||
}else if(strstr(icon,"04")!=NULL){
|
||||
iconofset = 3;
|
||||
}else if(strstr(icon,"09")!=NULL){
|
||||
iconofset = 4;
|
||||
}else if(strstr(icon,"10")!=NULL){
|
||||
iconofset = 5;
|
||||
}else if(strstr(icon,"11")!=NULL){
|
||||
iconofset = 6;
|
||||
}else if(strstr(icon,"13")!=NULL){
|
||||
iconofset = 7;
|
||||
}else if(strstr(icon,"50")!=NULL){
|
||||
iconofset = 8;
|
||||
}else{
|
||||
iconofset = 9;
|
||||
}
|
||||
putcmd("cond_img.pic", 50+iconofset);
|
||||
weatherVisible(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Nextion::getWeather(void * pvParameters){
|
||||
delay(200);
|
||||
if (nextion.getForecast()) {
|
||||
// nextion.weatherRequest = true;
|
||||
weatherticker.detach();
|
||||
weatherticker.attach(WEATHER_REQUEST_INTERVAL, nextion.updateWeather);
|
||||
} else {
|
||||
weatherticker.detach();
|
||||
weatherticker.attach(WEATHER_REQUEST_INTERVAL_FAULTY, nextion.updateWeather);
|
||||
}
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
|
||||
void Nextion::updateWeather() {
|
||||
if(strlen(config.store.weatherkey)==0 || !config.store.showweather) {
|
||||
nextion.weatherVisible(0);
|
||||
return;
|
||||
}
|
||||
xTaskCreatePinnedToCore(
|
||||
nextion.getWeather, /* Task function. */
|
||||
"nextiongetWeather", /* name of task. */
|
||||
1024 * 4, /* Stack size of task */
|
||||
NULL, /* parameter of the task */
|
||||
0, /* priority of the task */
|
||||
&nextion.weatherUpdateTaskHandle, /* Task handle to keep track of created task */
|
||||
0); /* pin task to core 0 */
|
||||
}
|
||||
|
||||
void Nextion::startWeather(){
|
||||
updateWeather();
|
||||
}
|
||||
|
||||
void Nextion::sleep(void) {
|
||||
putcmd("sleep=1");
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#ifndef NEXTION_H
|
||||
#define NEXTION_H
|
||||
|
||||
//#include <SoftwareSerial.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include "../../display.h"
|
||||
#include "../core/display.h"
|
||||
|
||||
#define TXBUFLEN 255
|
||||
#define RXBUFLEN 50
|
||||
@@ -17,9 +16,6 @@
|
||||
#define ICON_MP3 ICON_NA+3
|
||||
#define ICON_WAV ICON_NA+4
|
||||
|
||||
#define WEATHER_REQUEST_INTERVAL 1800 //30min
|
||||
#define WEATHER_REQUEST_INTERVAL_FAULTY 30
|
||||
|
||||
class Nextion {
|
||||
private:
|
||||
char txbuf[TXBUFLEN];
|
||||
@@ -31,16 +27,12 @@ class Nextion {
|
||||
QueueHandle_t _displayQueue=NULL;
|
||||
bool _dummyDisplay;
|
||||
bool _volInside;
|
||||
Ticker _timer;
|
||||
unsigned long _volDelay;
|
||||
void createCore0Task();
|
||||
void processQueue();
|
||||
void drawVU();
|
||||
public:
|
||||
displayMode_e mode;
|
||||
bool dt;
|
||||
TaskHandle_t weatherUpdateTaskHandle;
|
||||
// bool weatherRequest;
|
||||
public:
|
||||
Nextion();
|
||||
void begin(bool dummy=false);
|
||||
@@ -60,6 +52,7 @@ class Nextion {
|
||||
void printClock(struct tm timeinfo);
|
||||
void bitrate(int bpm);
|
||||
void bitratePic(uint8_t pic);
|
||||
void audioinfo(const char* info);
|
||||
void rssi();
|
||||
void weatherVisible(uint8_t vis);
|
||||
void localTime(struct tm timeinfo);
|
||||
@@ -67,12 +60,8 @@ class Nextion {
|
||||
void swichMode(displayMode_e newmode);
|
||||
void drawNextStationNum(uint16_t num);
|
||||
void putRequest(requestParams_t request);
|
||||
void startWeather();
|
||||
bool getForecast();
|
||||
static void updateWeather();
|
||||
static void getWeather(void * pvParameters);
|
||||
void sleep();
|
||||
void wake();
|
||||
void sleep();
|
||||
void wake();
|
||||
};
|
||||
|
||||
extern Nextion nextion;
|
||||
|
||||
82
yoRadio/src/displays/tools/commongfx.h
Normal file
82
yoRadio/src/displays/tools/commongfx.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef common_gfx_h
|
||||
#define common_gfx_h
|
||||
|
||||
public:
|
||||
DspCore();
|
||||
char plMenu[PLMITEMS][PLMITEMLENGHT];
|
||||
void initDisplay();
|
||||
void drawLogo(uint16_t top);
|
||||
void clearDsp(bool black=false);
|
||||
void printClock(){}
|
||||
void printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw);
|
||||
void clearClock();
|
||||
char* utf8Rus(const char* str, bool uppercase);
|
||||
void drawPlaylist(uint16_t currentItem, char* currentItemText);
|
||||
void loop(bool force=false);
|
||||
void charSize(uint8_t textsize, uint8_t& width, uint16_t& height);
|
||||
#ifndef DSP_LCD
|
||||
#if DSP_MODEL==DSP_NOKIA5110
|
||||
virtual void command(uint8_t c);
|
||||
virtual void data(uint8_t c);
|
||||
#else
|
||||
virtual void startWrite(void);
|
||||
virtual void endWrite(void);
|
||||
#endif
|
||||
void setTextSize(uint8_t s);
|
||||
#else
|
||||
uint16_t width();
|
||||
uint16_t height();
|
||||
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){}
|
||||
void setTextSize(uint8_t s){}
|
||||
void setTextSize(uint8_t sx, uint8_t sy){}
|
||||
void setTextColor(uint16_t c, uint16_t bg){}
|
||||
void setFont(){}
|
||||
void apScreen();
|
||||
#endif
|
||||
|
||||
void flip();
|
||||
void invert();
|
||||
void sleep();
|
||||
void wake();
|
||||
void writePixel(int16_t x, int16_t y, uint16_t color);
|
||||
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void setClipping(clipArea ca);
|
||||
void clearClipping();
|
||||
void setScrollId(void * scrollid) { _scrollid = scrollid; }
|
||||
void * getScrollId() { return _scrollid; }
|
||||
void setNumFont();
|
||||
uint16_t textWidth(const char *txt);
|
||||
#if DSP_MODEL==DSP_ILI9225
|
||||
uint16_t width(void) { return (int16_t)maxX(); }
|
||||
uint16_t height(void) { return (int16_t)maxY(); }
|
||||
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t *bitmap, int16_t w, int16_t h);
|
||||
uint16_t print(const char* s);
|
||||
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void setFont(const GFXfont *f = NULL);
|
||||
void setFont(uint8_t* font, bool monoSp=false );
|
||||
void setTextColor(uint16_t fg, uint16_t bg);
|
||||
void setCursor(int16_t x, int16_t y);
|
||||
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
uint16_t drawChar(uint16_t x, uint16_t y, uint16_t ch, uint16_t color = COLOR_WHITE);
|
||||
#endif
|
||||
private:
|
||||
char _timeBuf[20], _dateBuf[20], _oldTimeBuf[20], _oldDateBuf[20], _bufforseconds[4], _buffordate[40];
|
||||
uint16_t _timewidth, _timeleft, _datewidth, _dateleft, _oldtimeleft, _oldtimewidth, _olddateleft, _olddatewidth, clockTop, clockRightSpace, clockTimeHeight, _dotsLeft;
|
||||
bool _clipping, _printdots;
|
||||
clipArea _cliparea;
|
||||
void * _scrollid;
|
||||
void _getTimeBounds();
|
||||
void _clockSeconds();
|
||||
void _clockDate();
|
||||
void _clockTime();
|
||||
uint8_t _charWidth(unsigned char c);
|
||||
#if DSP_MODEL==DSP_ILI9225
|
||||
uint16_t _bgcolor, _fgcolor;
|
||||
int16_t _cursorx, _cursory;
|
||||
bool _gFont/*, _started*/;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
18
yoRadio/src/displays/tools/l10n.h
Normal file
18
yoRadio/src/displays/tools/l10n.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _display_l10n_h
|
||||
#define _display_l10n_h
|
||||
|
||||
//==================================================
|
||||
#if L10N_LANGUAGE==RU
|
||||
#define L10N_PATH "../../../locale/displayL10n_ru.h"
|
||||
#else
|
||||
#define L10N_PATH "../../../locale/displayL10n_en.h"
|
||||
#endif
|
||||
|
||||
#if __has_include("../../../locale/displayL10n_custom.h")
|
||||
#include "../../../locale/displayL10n_custom.h"
|
||||
#else
|
||||
#include L10N_PATH
|
||||
#endif
|
||||
//==================================================
|
||||
|
||||
#endif
|
||||
@@ -1,15 +1,5 @@
|
||||
#include "../../options.h"
|
||||
#if DSP_MODEL==0
|
||||
|
||||
#include "displayDummy.h"
|
||||
#include <SPI.h>
|
||||
#include "../../player.h"
|
||||
#include "../../config.h"
|
||||
#include "../../network.h"
|
||||
|
||||
DspCore::DspCore() {
|
||||
|
||||
}
|
||||
#ifndef utf8RusGFX_h
|
||||
#define utf8RusGFX_h
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
@@ -85,92 +75,4 @@ char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
return strn;
|
||||
}
|
||||
|
||||
void DspCore::apScreen() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::initD(uint16_t &screenwidth, uint16_t &screenheight) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawLogo() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::clearDsp() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawScrollFrame(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::getScrolBbounds(const char* text, const char* separator, byte textsize, uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::displayHeapForDebug() {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printClock(const char* timestr) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawVolumeBar(bool withNumber) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::drawNextStationNum(uint16_t num) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::frameTitle(const char* str) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::rssi(const char* str) {
|
||||
;
|
||||
}
|
||||
|
||||
void DspCore::ip(const char* str) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::set_TextSize(uint8_t s) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::set_TextColor(uint16_t fg, uint16_t bg) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::set_Cursor(int16_t x, int16_t y) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::printText(const char* txt) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
111
yoRadio/src/displays/tools/utf8RusLCD.h
Normal file
111
yoRadio/src/displays/tools/utf8RusLCD.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef utf8RusLCD_h
|
||||
#define utf8RusLCD_h
|
||||
|
||||
char* DspCore::utf8Rus(const char* str, bool uppercase) {
|
||||
int index = 0;
|
||||
static char strn[BUFLEN];
|
||||
static char newStr[BUFLEN];
|
||||
bool E = false;
|
||||
strlcpy(strn, str, BUFLEN);
|
||||
newStr[0] = '\0';
|
||||
bool next = false;
|
||||
for (char *iter = strn; *iter != '\0'; ++iter)
|
||||
{
|
||||
if (E) {
|
||||
E = false;
|
||||
continue;
|
||||
}
|
||||
byte rus = (byte) * iter;
|
||||
if (rus == 208 && (byte) * (iter + 1) == 129) { // ёКостыли
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (rus == 209 && (byte) * (iter + 1) == 145) {
|
||||
*iter = (char)209;
|
||||
*(iter + 1) = (char)145;
|
||||
E = true;
|
||||
continue;
|
||||
}
|
||||
if (next) {
|
||||
if (rus >= 128 && rus <= 143) *iter = (char)(rus + 32);
|
||||
if (rus >= 176 && rus <= 191) *iter = (char)(rus - 32);
|
||||
next = false;
|
||||
}
|
||||
if (rus == 208) next = true;
|
||||
if (rus == 209) {
|
||||
*iter = (char)208;
|
||||
next = true;
|
||||
}
|
||||
*iter = toupper(*iter);
|
||||
}
|
||||
|
||||
while (strn[index])
|
||||
{
|
||||
if (strlen(newStr) > BUFLEN - 2) break;
|
||||
if (strn[index] >= 0xBF)
|
||||
{
|
||||
switch (strn[index]) {
|
||||
case 0xD0: {
|
||||
switch (strn[index + 1])
|
||||
{
|
||||
case 0x90: strcat(newStr, "A"); break;
|
||||
case 0x91: strcat(newStr, "B"); break;
|
||||
case 0x92: strcat(newStr, "V"); break;
|
||||
case 0x93: strcat(newStr, "G"); break;
|
||||
case 0x94: strcat(newStr, "D"); break;
|
||||
case 0x95: strcat(newStr, "E"); break;
|
||||
case 0x96: strcat(newStr, "ZH"); break;
|
||||
case 0x97: strcat(newStr, "Z"); break;
|
||||
case 0x98: strcat(newStr, "I"); break;
|
||||
case 0x99: strcat(newStr, "Y"); break;
|
||||
case 0x9A: strcat(newStr, "K"); break;
|
||||
case 0x9B: strcat(newStr, "L"); break;
|
||||
case 0x9C: strcat(newStr, "M"); break;
|
||||
case 0x9D: strcat(newStr, "N"); break;
|
||||
case 0x9E: strcat(newStr, "O"); break;
|
||||
case 0x9F: strcat(newStr, "P"); break;
|
||||
case 0xA0: strcat(newStr, "R"); break;
|
||||
case 0xA1: strcat(newStr, "S"); break;
|
||||
case 0xA2: strcat(newStr, "T"); break;
|
||||
case 0xA3: strcat(newStr, "U"); break;
|
||||
case 0xA4: strcat(newStr, "F"); break;
|
||||
case 0xA5: strcat(newStr, "H"); break;
|
||||
case 0xA6: strcat(newStr, "TS"); break;
|
||||
case 0xA7: strcat(newStr, "CH"); break;
|
||||
case 0xA8: strcat(newStr, "SH"); break;
|
||||
case 0xA9: strcat(newStr, "SHCH"); break;
|
||||
case 0xAA: strcat(newStr, "'"); break;
|
||||
case 0xAB: strcat(newStr, "YU"); break;
|
||||
case 0xAC: strcat(newStr, "'"); break;
|
||||
case 0xAD: strcat(newStr, "E"); break;
|
||||
case 0xAE: strcat(newStr, "YU"); break;
|
||||
case 0xAF: strcat(newStr, "YA"); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xD1: {
|
||||
if (strn[index + 1] == 0x91) {
|
||||
strcat(newStr, "YO"); break;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
int sind = index + 2;
|
||||
while (strn[sind]) {
|
||||
strn[sind - 1] = strn[sind];
|
||||
sind++;
|
||||
}
|
||||
strn[sind - 1] = 0;
|
||||
} else {
|
||||
char Temp[2] = {(char) strn[index] , 0 } ;
|
||||
strcat(newStr, Temp);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return newStr;
|
||||
}
|
||||
|
||||
#endif
|
||||
78
yoRadio/src/displays/widgets/pages.cpp
Normal file
78
yoRadio/src/displays/widgets/pages.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "../dspcore.h"
|
||||
#if DSP_MODEL!=DSP_DUMMY
|
||||
|
||||
#include "pages.h"
|
||||
|
||||
void Pager::begin(){
|
||||
|
||||
}
|
||||
|
||||
void Pager::loop(){
|
||||
for(const auto& p: _pages)
|
||||
if(p->isActive()) p->loop();
|
||||
}
|
||||
|
||||
Page& Pager::addPage(Page* page, bool setNow){
|
||||
_pages.add(page);
|
||||
if(setNow) setPage(page);
|
||||
return *page;
|
||||
}
|
||||
|
||||
bool Pager::removePage(Page* page){
|
||||
page->setActive(false);
|
||||
dsp.clearDsp();
|
||||
return _pages.remove(page);
|
||||
}
|
||||
|
||||
void Pager::setPage(Page* page, bool black){
|
||||
for(const auto& p: _pages) p->setActive(false);
|
||||
dsp.clearDsp(black);
|
||||
page->setActive(true);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
Page::Page() : _widgets(LinkedList<Widget * >([](Widget * wd) { delete wd;})), _pages(LinkedList<Page*>([](Page* pg){ delete pg; })) {
|
||||
_active = false;
|
||||
}
|
||||
|
||||
Page::~Page() {
|
||||
for (const auto& w : _widgets) removeWidget(w);
|
||||
}
|
||||
|
||||
void Page::loop() {
|
||||
if(_active) for (const auto& w : _widgets) w->loop();
|
||||
}
|
||||
|
||||
Widget& Page::addWidget(Widget* widget) {
|
||||
_widgets.add(widget);
|
||||
widget->setActive(_active, _active);
|
||||
return *widget;
|
||||
}
|
||||
|
||||
bool Page::removeWidget(Widget* widget){
|
||||
widget->setActive(false, _active);
|
||||
return _widgets.remove(widget);
|
||||
}
|
||||
|
||||
Page& Page::addPage(Page* page){
|
||||
_pages.add(page);
|
||||
return *page;
|
||||
}
|
||||
|
||||
bool Page::removePage(Page* page){
|
||||
return _pages.remove(page);
|
||||
}
|
||||
|
||||
void Page::setActive(bool act) {
|
||||
for(const auto& w: _widgets) w->setActive(act);
|
||||
for(const auto& p: _pages) p->setActive(act);
|
||||
_active = act;
|
||||
}
|
||||
|
||||
bool Page::isActive() {
|
||||
return _active;
|
||||
}
|
||||
|
||||
#endif // #if DSP_MODEL!=DSP_DUMMY
|
||||
38
yoRadio/src/displays/widgets/pages.h
Normal file
38
yoRadio/src/displays/widgets/pages.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef pages_h
|
||||
#define pages_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "StringArray.h"
|
||||
|
||||
class Page {
|
||||
protected:
|
||||
LinkedList<Widget*> _widgets;
|
||||
LinkedList<Page*> _pages;
|
||||
bool _active;
|
||||
public:
|
||||
Page();
|
||||
~Page();
|
||||
void loop();
|
||||
Widget& addWidget(Widget* widget);
|
||||
bool removeWidget(Widget* widget);
|
||||
Page& addPage(Page* page);
|
||||
bool removePage(Page* page);
|
||||
void setActive(bool act);
|
||||
bool isActive();
|
||||
};
|
||||
|
||||
class Pager{
|
||||
public:
|
||||
Pager() : _pages(LinkedList<Page*>([](Page* pg){ delete pg; })) {}
|
||||
void begin();
|
||||
void loop();
|
||||
Page& addPage(Page* page, bool setNow = false);
|
||||
bool removePage(Page* page);
|
||||
void setPage(Page* page, bool black=false);
|
||||
private:
|
||||
LinkedList<Page*> _pages;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
494
yoRadio/src/displays/widgets/widgets.cpp
Normal file
494
yoRadio/src/displays/widgets/widgets.cpp
Normal file
@@ -0,0 +1,494 @@
|
||||
#include "../dspcore.h"
|
||||
#if DSP_MODEL!=DSP_DUMMY
|
||||
|
||||
#include "widgets.h"
|
||||
#include "../../core/player.h" // for VU widget
|
||||
|
||||
/************************
|
||||
FILL WIDGET
|
||||
************************/
|
||||
void FillWidget::init(FillConfig conf, uint16_t bgcolor){
|
||||
Widget::init(conf.widget, bgcolor, bgcolor);
|
||||
_width = conf.width;
|
||||
_height = conf.height;
|
||||
|
||||
}
|
||||
|
||||
void FillWidget::_draw(){
|
||||
if(!_active) return;
|
||||
dsp.fillRect(_config.left, _config.top, _width, _height, _bgcolor);
|
||||
}
|
||||
|
||||
/************************
|
||||
TEXT WIDGET
|
||||
************************/
|
||||
TextWidget::~TextWidget() {
|
||||
free(_text);
|
||||
free(_oldtext);
|
||||
}
|
||||
|
||||
void TextWidget::init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, fgcolor, bgcolor);
|
||||
_buffsize = buffsize;
|
||||
_text = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_text, 0, _buffsize);
|
||||
_oldtext = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_oldtext, 0, _buffsize);
|
||||
//_charWidth = wconf.textsize * CHARWIDTH; // default GFX font
|
||||
//_textheight = wconf.textsize * CHARHEIGHT; // default GFX font
|
||||
dsp.charSize(_config.textsize, _charWidth, _textheight);
|
||||
_textwidth = _oldtextwidth = _oldleft = 0;
|
||||
_uppercase = uppercase;
|
||||
}
|
||||
|
||||
void TextWidget::setText(const char* txt) {
|
||||
strlcpy(_text, dsp.utf8Rus(txt, _uppercase), _buffsize);
|
||||
_textwidth = strlen(_text) * _charWidth;
|
||||
if (strcmp(_oldtext, _text) == 0) return;
|
||||
if (_active) dsp.fillRect(_oldleft == 0 ? _realLeft() : min(_oldleft, _realLeft()), _config.top, max(_oldtextwidth, _textwidth), _textheight, _bgcolor);
|
||||
_oldtextwidth = _textwidth;
|
||||
_oldleft = _realLeft();
|
||||
if (_active) _draw();
|
||||
}
|
||||
|
||||
void TextWidget::setText(int val, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, val);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
void TextWidget::setText(const char* txt, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, txt);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
uint16_t TextWidget::_realLeft() {
|
||||
switch (_config.align) {
|
||||
case WA_CENTER: return (dsp.width() - _textwidth) / 2; break;
|
||||
case WA_RIGHT: return (dsp.width() - _textwidth - _config.left); break;
|
||||
default: return _config.left; break;
|
||||
}
|
||||
}
|
||||
|
||||
void TextWidget::_draw() {
|
||||
if(!_active) return;
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
dsp.setFont();
|
||||
dsp.setTextSize(_config.textsize);
|
||||
dsp.print(_text);
|
||||
strlcpy(_oldtext, _text, _buffsize);
|
||||
}
|
||||
|
||||
/************************
|
||||
SCROLL WIDGET
|
||||
************************/
|
||||
ScrollWidget::ScrollWidget(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
init(separator, conf, fgcolor, bgcolor);
|
||||
}
|
||||
|
||||
ScrollWidget::~ScrollWidget() {
|
||||
free(_sep);
|
||||
free(_window);
|
||||
}
|
||||
|
||||
void ScrollWidget::init(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
TextWidget::init(conf.widget, conf.buffsize, conf.uppercase, fgcolor, bgcolor);
|
||||
_sep = (char *) malloc(sizeof(char) * 4);
|
||||
memset(_sep, 0, 4);
|
||||
snprintf(_sep, 4, " %.*s ", 1, separator);
|
||||
_x = conf.widget.left;
|
||||
_startscrolldelay = conf.startscrolldelay;
|
||||
_scrolldelta = conf.scrolldelta;
|
||||
_scrolltime = conf.scrolltime;
|
||||
//_charWidth = CHARWIDTH * _config.textsize; // default GFX font
|
||||
//_textheight = CHARHEIGHT * _config.textsize; // default GFX font
|
||||
dsp.charSize(_config.textsize, _charWidth, _textheight);
|
||||
_sepwidth = strlen(_sep) * _charWidth;
|
||||
_width = conf.width;
|
||||
_backMove.width = _width;
|
||||
_window = (char *) malloc(sizeof(char) * (MAX_WIDTH / _charWidth + 1));
|
||||
memset(_window, 0, (MAX_WIDTH / _charWidth + 1)); // +1?
|
||||
_doscroll = false;
|
||||
}
|
||||
|
||||
void ScrollWidget::_setTextParams() {
|
||||
if (_config.textsize == 0) return;
|
||||
dsp.setTextSize(_config.textsize);
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
}
|
||||
|
||||
bool ScrollWidget::_checkIsScrollNeeded() {
|
||||
return _textwidth > _width;
|
||||
}
|
||||
|
||||
void ScrollWidget::setText(const char* txt) {
|
||||
strlcpy(_text, dsp.utf8Rus(txt, _uppercase), _buffsize - 1);
|
||||
if (strcmp(_oldtext, _text) == 0) return;
|
||||
_textwidth = strlen(_text) * _charWidth;
|
||||
_x = _config.left;
|
||||
_doscroll = _checkIsScrollNeeded();
|
||||
if (dsp.getScrollId() == this) dsp.setScrollId(NULL);
|
||||
_scrolldelay = millis();
|
||||
if (_active) {
|
||||
_setTextParams();
|
||||
if (_doscroll) {
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
dsp.setCursor(_config.left, _config.top);
|
||||
snprintf(_window, _width / _charWidth + 1, "%s", _text); //TODO
|
||||
dsp.setClipping({_config.left, _config.top, _width, _textheight});
|
||||
dsp.print(_window);
|
||||
dsp.clearClipping();
|
||||
} else {
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
//dsp.setClipping({_config.left, _config.top, _width, _textheight});
|
||||
dsp.print(_text);
|
||||
//dsp.clearClipping();
|
||||
}
|
||||
strlcpy(_oldtext, _text, _buffsize);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::setText(const char* txt, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, txt);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
void ScrollWidget::loop() {
|
||||
if(_locked) return;
|
||||
if (!_doscroll || _config.textsize == 0 || (dsp.getScrollId() != NULL && dsp.getScrollId() != this)) return;
|
||||
if (_checkDelay(_x == _config.left ? _startscrolldelay : _scrolltime, _scrolldelay)) {
|
||||
_calcX();
|
||||
if (_active) _draw();
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::_clear(){
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
}
|
||||
|
||||
void ScrollWidget::_draw() {
|
||||
if(!_active || _locked) return;
|
||||
_setTextParams();
|
||||
if (_doscroll) {
|
||||
uint16_t _newx = _config.left - _x;
|
||||
const char* _cursor = _text + _newx / _charWidth;
|
||||
uint16_t hiddenChars = _cursor - _text;
|
||||
if (hiddenChars < strlen(_text)) {
|
||||
snprintf(_window, _width / _charWidth + 1, "%s%s%s", _cursor, _sep, _text);
|
||||
} else {
|
||||
const char* _scursor = _sep + (_cursor - (_text + strlen(_text)));
|
||||
snprintf(_window, _width / _charWidth + 1, "%s%s", _scursor, _text);
|
||||
}
|
||||
dsp.setCursor(_x + hiddenChars * _charWidth, _config.top);
|
||||
dsp.setClipping({_config.left, _config.top, _width, _textheight});
|
||||
dsp.print(_window);
|
||||
#ifndef DSP_LCD
|
||||
dsp.print(" ");
|
||||
#endif
|
||||
dsp.clearClipping();
|
||||
} else {
|
||||
dsp.fillRect(_config.left, _config.top, _width, _textheight, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
dsp.setClipping({_realLeft(), _config.top, _width, _textheight});
|
||||
dsp.print(_text);
|
||||
dsp.clearClipping();
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::_calcX() {
|
||||
if (!_doscroll || _config.textsize == 0) return;
|
||||
_x -= _scrolldelta;
|
||||
if (-_x > _textwidth + _sepwidth - _config.left) {
|
||||
_x = _config.left;
|
||||
dsp.setScrollId(NULL);
|
||||
} else {
|
||||
dsp.setScrollId(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScrollWidget::_checkDelay(int m, uint32_t &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollWidget::_reset(){
|
||||
dsp.setScrollId(NULL);
|
||||
_x = _config.left;
|
||||
_scrolldelay = millis();
|
||||
_doscroll = _checkIsScrollNeeded();
|
||||
}
|
||||
|
||||
/************************
|
||||
SLIDER WIDGET
|
||||
************************/
|
||||
void SliderWidget::init(FillConfig conf, uint16_t fgcolor, uint16_t bgcolor, uint32_t maxval, uint16_t oucolor) {
|
||||
Widget::init(conf.widget, fgcolor, bgcolor);
|
||||
_width = conf.width; _height = conf.height; _outlined = conf.outlined; _oucolor = oucolor, _max = maxval;
|
||||
_oldvalwidth = _value = 0;
|
||||
}
|
||||
|
||||
void SliderWidget::setValue(uint32_t val) {
|
||||
_value = val;
|
||||
if (_active && !_locked) _drawslider();
|
||||
|
||||
}
|
||||
|
||||
void SliderWidget::_drawslider() {
|
||||
uint16_t valwidth = map(_value, 0, _max, 0, _width - _outlined * 2);
|
||||
if (_oldvalwidth == valwidth) return;
|
||||
dsp.fillRect(_config.left + _outlined + min(valwidth, _oldvalwidth), _config.top + _outlined, abs(_oldvalwidth - valwidth), _height - _outlined * 2, _oldvalwidth > valwidth ? _bgcolor : _fgcolor);
|
||||
_oldvalwidth = valwidth;
|
||||
}
|
||||
|
||||
void SliderWidget::_draw() {
|
||||
if(_locked) return;
|
||||
_clear();
|
||||
if(!_active) return;
|
||||
if (_outlined) dsp.drawRect(_config.left, _config.top, _width, _height, _oucolor);
|
||||
uint16_t valwidth = map(_value, 0, _max, 0, _width - _outlined * 2);
|
||||
dsp.fillRect(_config.left + _outlined, _config.top + _outlined, valwidth, _height - _outlined * 2, _fgcolor);
|
||||
}
|
||||
|
||||
void SliderWidget::_clear() {
|
||||
_oldvalwidth = 0;
|
||||
dsp.fillRect(_config.left, _config.top, _width, _height, _bgcolor);
|
||||
}
|
||||
/************************
|
||||
VU WIDGET
|
||||
************************/
|
||||
#if !defined(DSP_LCD) && !defined(DSP_OLED)
|
||||
VuWidget::~VuWidget() {
|
||||
if(_canvas) free(_canvas);
|
||||
}
|
||||
|
||||
void VuWidget::init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, bgcolor, bgcolor);
|
||||
_vumaxcolor = vumaxcolor;
|
||||
_vumincolor = vumincolor;
|
||||
_bands = bands;
|
||||
_canvas = new Canvas(_bands.width * 2 + _bands.space, _bands.height);
|
||||
}
|
||||
|
||||
void VuWidget::_draw(){
|
||||
if(!_active || _locked) return;
|
||||
#if !defined(USE_NEXTION) && I2S_DOUT==255
|
||||
static uint8_t cc = 0;
|
||||
cc++;
|
||||
if(cc>1){
|
||||
player.getVUlevel();
|
||||
cc=0;
|
||||
}
|
||||
#endif
|
||||
static uint16_t measL, measR;
|
||||
uint16_t bandColor;
|
||||
uint16_t dimension = _config.align?_bands.width:_bands.height;
|
||||
uint8_t L = map(player.vuLeft, 255, 0, 0, dimension);
|
||||
uint8_t R = map(player.vuRight, 255, 0, 0, dimension);
|
||||
bool played = player.isRunning();
|
||||
if(played){
|
||||
measL=(L>=measL)?measL + _bands.fadespeed:L;
|
||||
measR=(R>=measR)?measR + _bands.fadespeed:R;
|
||||
}else{
|
||||
if(measL<dimension) measL += _bands.fadespeed;
|
||||
if(measR<dimension) measR += _bands.fadespeed;
|
||||
}
|
||||
if(measL>dimension) measL=dimension;
|
||||
if(measR>dimension) measR=dimension;
|
||||
uint8_t h=(dimension/_bands.perheight)-_bands.vspace;
|
||||
_canvas->fillRect(0,0,_bands.width * 2 + _bands.space,_bands.height, _bgcolor);
|
||||
for(int i=0; i<dimension; i++){
|
||||
if(i%(dimension/_bands.perheight)==0){
|
||||
if(_config.align){
|
||||
#ifndef BOOMBOX_STYLE
|
||||
bandColor = (i>_bands.width-(_bands.width/_bands.perheight)*4)?_vumaxcolor:_vumincolor;
|
||||
_canvas->fillRect(i, 0, h, _bands.height, bandColor);
|
||||
_canvas->fillRect(i + _bands.width + _bands.space, 0, h, _bands.height, bandColor);
|
||||
#else
|
||||
bandColor = (i>(_bands.width/_bands.perheight))?_vumincolor:_vumaxcolor;
|
||||
_canvas->fillRect(i, 0, h, _bands.height, bandColor);
|
||||
bandColor = (i>_bands.width-(_bands.width/_bands.perheight)*3)?_vumaxcolor:_vumincolor;
|
||||
_canvas->fillRect(i + _bands.width + _bands.space, 0, h, _bands.height, bandColor);
|
||||
#endif
|
||||
}else{
|
||||
bandColor = (i<(_bands.height/_bands.perheight)*3)?_vumaxcolor:_vumincolor;
|
||||
_canvas->fillRect(0, i, _bands.width, h, bandColor);
|
||||
_canvas->fillRect(_bands.width + _bands.space, i, _bands.width, h, bandColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(_config.align){
|
||||
#ifndef BOOMBOX_STYLE
|
||||
_canvas->fillRect(_bands.width-measL, 0, measL, _bands.width, _bgcolor);
|
||||
_canvas->fillRect(_bands.width * 2 + _bands.space - measR, 0, measR, _bands.width, _bgcolor);
|
||||
dsp.drawRGBBitmap(_config.left, _config.top, _canvas->getBuffer(), _bands.width * 2 + _bands.space, _bands.height);
|
||||
#else
|
||||
_canvas->fillRect(0, 0, _bands.width-(_bands.width-measL), _bands.width, _bgcolor);
|
||||
_canvas->fillRect(_bands.width * 2 + _bands.space - measR, 0, measR, _bands.width, _bgcolor);
|
||||
dsp->drawRGBBitmap(_config.left, _config.top, _canvas->getBuffer(), _bands.width * 2 + _bands.space, _bands.height);
|
||||
#endif
|
||||
}else{
|
||||
_canvas->fillRect(0, 0, _bands.width, measL, _bgcolor);
|
||||
_canvas->fillRect(_bands.width + _bands.space, 0, _bands.width, measR, _bgcolor);
|
||||
dsp.drawRGBBitmap(_config.left, _config.top, _canvas->getBuffer(), _bands.width * 2 + _bands.space, _bands.height);
|
||||
}
|
||||
}
|
||||
|
||||
void VuWidget::loop(){
|
||||
if(_active || !_locked) _draw();
|
||||
}
|
||||
|
||||
void VuWidget::_clear(){
|
||||
dsp.fillRect(_config.left, _config.top, _bands.width * 2 + _bands.space, _bands.height, _bgcolor);
|
||||
}
|
||||
#else // DSP_LCD
|
||||
VuWidget::~VuWidget() { }
|
||||
void VuWidget::init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, bgcolor, bgcolor);
|
||||
}
|
||||
void VuWidget::_draw(){ }
|
||||
void VuWidget::loop(){ }
|
||||
void VuWidget::_clear(){ }
|
||||
#endif
|
||||
/************************
|
||||
NUM WIDGET
|
||||
************************/
|
||||
void NumWidget::init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
Widget::init(wconf, fgcolor, bgcolor);
|
||||
_buffsize = buffsize;
|
||||
_text = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_text, 0, _buffsize);
|
||||
_oldtext = (char *) malloc(sizeof(char) * _buffsize);
|
||||
memset(_oldtext, 0, _buffsize);
|
||||
_textwidth = _oldtextwidth = _oldleft = 0;
|
||||
_uppercase = uppercase;
|
||||
_textheight = wconf.textsize;
|
||||
}
|
||||
|
||||
void NumWidget::setText(const char* txt) {
|
||||
strlcpy(_text, txt, _buffsize);
|
||||
_getBounds();
|
||||
if (strcmp(_oldtext, _text) == 0) return;
|
||||
if (_active) dsp.fillRect(_oldleft == 0 ? _realLeft() : min(_oldleft, _realLeft()), _config.top-_textheight+1, max(_oldtextwidth, _textwidth), _textheight, _bgcolor);
|
||||
_oldtextwidth = _textwidth;
|
||||
_oldleft = _realLeft();
|
||||
if (_active) _draw();
|
||||
}
|
||||
|
||||
void NumWidget::setText(int val, const char *format){
|
||||
char buf[_buffsize];
|
||||
snprintf(buf, _buffsize, format, val);
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
void NumWidget::_getBounds() {
|
||||
_textwidth= dsp.textWidth(_text);
|
||||
}
|
||||
|
||||
void NumWidget::_draw() {
|
||||
if(!_active) return;
|
||||
dsp.setNumFont(); // --------------SetBigFont
|
||||
//dsp.setTextSize(1);
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
dsp.setCursor(_realLeft(), _config.top);
|
||||
dsp.print(_text);
|
||||
strlcpy(_oldtext, _text, _buffsize);
|
||||
dsp.setFont();
|
||||
}
|
||||
|
||||
/**************************
|
||||
PROGRESS WIDGET
|
||||
**************************/
|
||||
void ProgressWidget::_progress() {
|
||||
char buf[_width + 1];
|
||||
snprintf(buf, _width, "%*s%.*s%*s", _pg <= _barwidth ? 0 : _pg - _barwidth, "", _pg <= _barwidth ? _pg : 5, ".....", _width - _pg, "");
|
||||
_pg++; if (_pg >= _width + _barwidth) _pg = 0;
|
||||
setText(buf);
|
||||
}
|
||||
|
||||
bool ProgressWidget::_checkDelay(int m, uint32_t &tstamp) {
|
||||
if (millis() - tstamp > m) {
|
||||
tstamp = millis();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressWidget::loop() {
|
||||
if (_checkDelay(_speed, _scrolldelay)) {
|
||||
_progress();
|
||||
}
|
||||
}
|
||||
|
||||
/**************************
|
||||
CLOCK WIDGET
|
||||
**************************/
|
||||
void ClockWidget::draw(){
|
||||
if(!_active) return;
|
||||
dsp.printClock(_config.top, _config.left, _config.textsize, false);
|
||||
}
|
||||
|
||||
void ClockWidget::_draw(){
|
||||
if(!_active) return;
|
||||
dsp.printClock(_config.top, _config.left, _config.textsize, true);
|
||||
}
|
||||
|
||||
void ClockWidget::_clear(){
|
||||
dsp.clearClock();
|
||||
}
|
||||
|
||||
void BitrateWidget::init(BitrateConfig bconf, uint16_t fgcolor, uint16_t bgcolor){
|
||||
Widget::init(bconf.widget, fgcolor, bgcolor);
|
||||
_dimension = bconf.dimension;
|
||||
_bitrate = 0;
|
||||
_format = BF_UNCNOWN;
|
||||
dsp.charSize(bconf.widget.textsize, _charWidth, _textheight);
|
||||
memset(_buf, 0, 6);
|
||||
}
|
||||
|
||||
void BitrateWidget::setBitrate(uint16_t bitrate){
|
||||
_bitrate = bitrate;
|
||||
_draw();
|
||||
}
|
||||
|
||||
void BitrateWidget::setFormat(BitrateFormat format){
|
||||
_format = format;
|
||||
_draw();
|
||||
}
|
||||
|
||||
void BitrateWidget::_draw(){
|
||||
_clear();
|
||||
if(!_active || _format == BF_UNCNOWN || _bitrate==0) return;
|
||||
dsp.drawRect(_config.left, _config.top, _dimension, _dimension, _fgcolor);
|
||||
dsp.fillRect(_config.left, _config.top + _dimension/2, _dimension, _dimension/2, _fgcolor);
|
||||
dsp.setFont();
|
||||
dsp.setTextSize(_config.textsize);
|
||||
dsp.setTextColor(_fgcolor, _bgcolor);
|
||||
snprintf(_buf, 6, "%d", _bitrate);
|
||||
dsp.setCursor(_config.left + _dimension/2 - _charWidth*strlen(_buf)/2, _config.top + _dimension/4 - _textheight/2+1);
|
||||
dsp.print(_buf);
|
||||
dsp.setTextColor(_bgcolor, _fgcolor);
|
||||
dsp.setCursor(_config.left + _dimension/2 - _charWidth*3/2, _config.top + _dimension - _dimension/4 - _textheight/2);
|
||||
switch(_format){
|
||||
case BF_MP3: dsp.print("MP3"); break;
|
||||
case BF_AAC: dsp.print("AAC"); break;
|
||||
case BF_FLAC: dsp.print("FLC"); break;
|
||||
case BF_OGG: dsp.print("OGG"); break;
|
||||
case BF_WAV: dsp.print("WAV"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void BitrateWidget::_clear() {
|
||||
dsp.fillRect(_config.left, _config.top, _dimension, _dimension, _bgcolor);
|
||||
}
|
||||
|
||||
#endif // #if DSP_MODEL!=DSP_DUMMY
|
||||
267
yoRadio/src/displays/widgets/widgets.h
Normal file
267
yoRadio/src/displays/widgets/widgets.h
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifndef widgets_h
|
||||
#define widgets_h
|
||||
|
||||
#include "Arduino.h"
|
||||
//#include "../../core/config.h"
|
||||
enum WidgetAlign { WA_LEFT, WA_CENTER, WA_RIGHT };
|
||||
enum BitrateFormat { BF_UNCNOWN, BF_MP3, BF_AAC, BF_FLAC, BF_OGG, BF_WAV };
|
||||
|
||||
typedef struct clipArea {
|
||||
uint16_t left;
|
||||
uint16_t top;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} clipArea;
|
||||
|
||||
struct WidgetConfig {
|
||||
uint16_t left;
|
||||
uint16_t top;
|
||||
uint16_t textsize;
|
||||
WidgetAlign align;
|
||||
};
|
||||
|
||||
struct ScrollConfig {
|
||||
WidgetConfig widget;
|
||||
uint16_t buffsize;
|
||||
bool uppercase;
|
||||
uint16_t width;
|
||||
uint16_t startscrolldelay;
|
||||
uint8_t scrolldelta;
|
||||
uint16_t scrolltime;
|
||||
};
|
||||
|
||||
struct FillConfig {
|
||||
WidgetConfig widget;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
bool outlined;
|
||||
};
|
||||
|
||||
struct ProgressConfig {
|
||||
uint16_t speed;
|
||||
uint16_t width;
|
||||
uint16_t barwidth;
|
||||
};
|
||||
|
||||
struct VUBandsConfig {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t space;
|
||||
uint8_t vspace;
|
||||
uint8_t perheight;
|
||||
uint8_t fadespeed;
|
||||
};
|
||||
|
||||
struct MoveConfig {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
int16_t width;
|
||||
};
|
||||
|
||||
struct BitrateConfig {
|
||||
WidgetConfig widget;
|
||||
uint16_t dimension;
|
||||
};
|
||||
|
||||
class Widget{
|
||||
public:
|
||||
Widget(){ _active = false; }
|
||||
virtual ~Widget(){}
|
||||
virtual void loop(){}
|
||||
virtual void init(WidgetConfig conf, uint16_t fgcolor, uint16_t bgcolor){
|
||||
_config = conf;
|
||||
_fgcolor = fgcolor;
|
||||
_bgcolor = bgcolor;
|
||||
_width = _backMove.width = 0;
|
||||
_backMove.x = _config.left;
|
||||
_backMove.y = _config.top;
|
||||
_moved = _locked = false;
|
||||
}
|
||||
void setAlign(WidgetAlign align){
|
||||
_config.align = align;
|
||||
}
|
||||
void setActive(bool act, bool clr=false) { _active = act; if(_active && !_locked) _draw(); if(clr && !_locked) _clear(); }
|
||||
void lock(bool lck=true) { _locked = lck; if(_locked) _reset(); if(_locked && _active) _clear(); }
|
||||
void unlock() { _locked = false; }
|
||||
bool locked() { return _locked; }
|
||||
void moveTo(MoveConfig mv){
|
||||
if(mv.width<0) return;
|
||||
_moved = true;
|
||||
if(_active && !_locked) _clear();
|
||||
_config.left = mv.x;
|
||||
_config.top = mv.y;
|
||||
if(mv.width>0) _width = mv.width;
|
||||
_reset();
|
||||
_draw();
|
||||
}
|
||||
void moveBack(){
|
||||
if(!_moved) return;
|
||||
if(_active && !_locked) _clear();
|
||||
_config.left = _backMove.x;
|
||||
_config.top = _backMove.y;
|
||||
_width = _backMove.width;
|
||||
_moved = false;
|
||||
_reset();
|
||||
_draw();
|
||||
}
|
||||
protected:
|
||||
bool _active, _moved, _locked;
|
||||
uint16_t _fgcolor, _bgcolor, _width;
|
||||
WidgetConfig _config;
|
||||
MoveConfig _backMove;
|
||||
virtual void _draw() {}
|
||||
virtual void _clear() {}
|
||||
virtual void _reset() {}
|
||||
};
|
||||
|
||||
class TextWidget: public Widget {
|
||||
public:
|
||||
TextWidget() {}
|
||||
TextWidget(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor) { init(wconf, buffsize, uppercase, fgcolor, bgcolor); }
|
||||
~TextWidget();
|
||||
void init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void setText(const char* txt);
|
||||
void setText(int val, const char *format);
|
||||
void setText(const char* txt, const char *format);
|
||||
bool uppercase() { return _uppercase; }
|
||||
protected:
|
||||
char *_text;
|
||||
char *_oldtext;
|
||||
bool _uppercase;
|
||||
uint16_t _buffsize, _textwidth, _oldtextwidth, _oldleft, _textheight;
|
||||
uint8_t _charWidth;
|
||||
protected:
|
||||
void _draw();
|
||||
uint16_t _realLeft();
|
||||
};
|
||||
|
||||
class FillWidget: public Widget {
|
||||
public:
|
||||
FillWidget() {}
|
||||
FillWidget(FillConfig conf, uint16_t bgcolor) { init(conf, bgcolor); }
|
||||
void init(FillConfig conf, uint16_t bgcolor);
|
||||
protected:
|
||||
uint16_t _height;
|
||||
void _draw();
|
||||
};
|
||||
|
||||
class ScrollWidget: public TextWidget {
|
||||
public:
|
||||
ScrollWidget(){}
|
||||
ScrollWidget(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor);
|
||||
~ScrollWidget();
|
||||
void init(const char* separator, ScrollConfig conf, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void loop();
|
||||
void setText(const char* txt);
|
||||
void setText(const char* txt, const char *format);
|
||||
private:
|
||||
char *_sep;
|
||||
char *_window;
|
||||
int16_t _x;
|
||||
bool _doscroll;
|
||||
uint8_t _scrolldelta;
|
||||
uint16_t _scrolltime;
|
||||
uint32_t _scrolldelay;
|
||||
uint16_t _sepwidth, _startscrolldelay;
|
||||
uint8_t _charWidth;
|
||||
private:
|
||||
void _setTextParams();
|
||||
void _calcX();
|
||||
void _drawFrame();
|
||||
void _draw();
|
||||
bool _checkIsScrollNeeded();
|
||||
bool _checkDelay(int m, uint32_t &tstamp);
|
||||
void _clear();
|
||||
void _reset();
|
||||
};
|
||||
|
||||
class SliderWidget: public Widget {
|
||||
public:
|
||||
SliderWidget(){}
|
||||
SliderWidget(FillConfig conf, uint16_t fgcolor, uint16_t bgcolor, uint32_t maxval, uint16_t oucolor=0){
|
||||
init(conf, fgcolor, bgcolor, maxval, oucolor);
|
||||
}
|
||||
void init(FillConfig conf, uint16_t fgcolor, uint16_t bgcolor, uint32_t maxval, uint16_t oucolor=0);
|
||||
void setValue(uint32_t val);
|
||||
protected:
|
||||
uint16_t _height, _oucolor, _oldvalwidth;
|
||||
uint32_t _max, _value;
|
||||
bool _outlined;
|
||||
void _draw();
|
||||
void _drawslider();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
class VuWidget: public Widget {
|
||||
public:
|
||||
VuWidget() {}
|
||||
VuWidget(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor) { init(wconf, bands, vumaxcolor, vumincolor, bgcolor); }
|
||||
~VuWidget();
|
||||
void init(WidgetConfig wconf, VUBandsConfig bands, uint16_t vumaxcolor, uint16_t vumincolor, uint16_t bgcolor);
|
||||
void loop();
|
||||
protected:
|
||||
#if !defined(DSP_LCD) && !defined(DSP_OLED)
|
||||
Canvas *_canvas;
|
||||
#endif
|
||||
VUBandsConfig _bands;
|
||||
uint16_t _vumaxcolor, _vumincolor;
|
||||
void _draw();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
class NumWidget: public TextWidget {
|
||||
public:
|
||||
void init(WidgetConfig wconf, uint16_t buffsize, bool uppercase, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void setText(const char* txt);
|
||||
void setText(int val, const char *format);
|
||||
protected:
|
||||
void _getBounds();
|
||||
void _draw();
|
||||
};
|
||||
|
||||
class ProgressWidget: public TextWidget {
|
||||
public:
|
||||
ProgressWidget() {}
|
||||
ProgressWidget(WidgetConfig conf, ProgressConfig pconf, uint16_t fgcolor, uint16_t bgcolor) {
|
||||
init(conf, pconf, fgcolor, bgcolor);
|
||||
}
|
||||
void init(WidgetConfig conf, ProgressConfig pconf, uint16_t fgcolor, uint16_t bgcolor){
|
||||
TextWidget::init(conf, pconf.width, false, fgcolor, bgcolor);
|
||||
_speed = pconf.speed; _width = pconf.width; _barwidth = pconf.barwidth;
|
||||
_pg = 0;
|
||||
}
|
||||
void loop();
|
||||
private:
|
||||
uint8_t _pg;
|
||||
uint16_t _speed, _barwidth;
|
||||
uint32_t _scrolldelay;
|
||||
void _progress();
|
||||
bool _checkDelay(int m, uint32_t &tstamp);
|
||||
};
|
||||
|
||||
class ClockWidget: public Widget {
|
||||
public:
|
||||
void draw();
|
||||
protected:
|
||||
void _draw();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
class BitrateWidget: public Widget {
|
||||
public:
|
||||
BitrateWidget() {}
|
||||
BitrateWidget(BitrateConfig bconf, uint16_t fgcolor, uint16_t bgcolor) { init(bconf, fgcolor, bgcolor); }
|
||||
~BitrateWidget(){}
|
||||
void init(BitrateConfig bconf, uint16_t fgcolor, uint16_t bgcolor);
|
||||
void setBitrate(uint16_t bitrate);
|
||||
void setFormat(BitrateFormat format);
|
||||
protected:
|
||||
BitrateFormat _format;
|
||||
char _buf[6];
|
||||
uint8_t _charWidth;
|
||||
uint16_t _dimension, _bitrate, _textheight;
|
||||
void _draw();
|
||||
void _clear();
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user