diff --git a/images/img3.jpg b/images/img3.jpg new file mode 100644 index 0000000..53551e2 Binary files /dev/null and b/images/img3.jpg differ diff --git a/yoRadio/controls.cpp b/yoRadio/controls.cpp index 3c8b73a..174bc25 100644 --- a/yoRadio/controls.cpp +++ b/yoRadio/controls.cpp @@ -36,6 +36,9 @@ void initControls() { void loopControls() { encbutton.tick(); + btnleft.tick(); + btncenter.tick(); + btnright.tick(); encoderLoop(); yield(); } diff --git a/yoRadio/display.cpp b/yoRadio/display.cpp index 33eac12..30c6c5b 100644 --- a/yoRadio/display.cpp +++ b/yoRadio/display.cpp @@ -7,14 +7,22 @@ #include "options.h" #include "network.h" -/* -// Without display -#include "displayDummy.h" +//#define DSP_DUMMY +//#define DSP_ST7735 +#define DSP_SSD1306 + +#ifdef DSP_DUMMY +#include "src/displays/displayDummy.h" DisplayDummy dsp; -*/ -// With ST7735 display -#include "displayST7735.h" +#endif +#ifdef DSP_ST7735 +#include "src/displays/displayST7735.h" DisplayST7735 dsp; +#endif +#ifdef DSP_SSD1306 +#include "src/displays/displaySSD1306.h" +DisplaySSD1306 dsp; +#endif Display display; @@ -129,7 +137,9 @@ void Display::init() { meta.init(" * ", 2, TFT_FRAMEWDT, STARTTIME, TFT_LOGO, TFT_BG); title1.init(" * ", 1, TFT_FRAMEWDT + 2 * TFT_LINEHGHT, STARTTIME, TFT_FG, TFT_BG); title2.init(" * ", 1, TFT_FRAMEWDT + 3 * TFT_LINEHGHT, STARTTIME, TFT_FG, TFT_BG); - plCurrent.init(" * ", 2, 57, 0, TFT_BG, TFT_LOGO); + int yStart = (screenheight / 2 - PLMITEMHEIGHT / 2) + 3; + //plCurrent.init(" * ", 2, 57, 0, TFT_BG, TFT_LOGO); + plCurrent.init(" * ", 2, yStart, 0, TFT_BG, TFT_LOGO); plCurrent.lock(); } @@ -237,6 +247,7 @@ void Display::loop() { break; } } + dsp.loop(); yield(); } @@ -246,6 +257,7 @@ void Display::centerText(const char* text, byte y, uint16_t fg, uint16_t bg) { void Display::bootString(const char* text, byte y) { dsp.centerText(text, y, TFT_LOGO, TFT_BG); + dsp.loop(); } void Display::rightText(const char* text, byte y, uint16_t fg, uint16_t bg) { diff --git a/yoRadio/options.h b/yoRadio/options.h index 3e396c3..dde3c43 100644 --- a/yoRadio/options.h +++ b/yoRadio/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define VERSION "0.4.170" +#define VERSION "0.4.177" /* * TFT DISPLAY @@ -18,13 +18,18 @@ //#define TFT_RST -1 // we use the seesaw for resetting to save a pin #define TFT_DC 4 +/* + * OLED I2C DISPLAY + */ +#define I2C_SDA 13 +#define I2C_SCL 14 +#define I2C_RST -1 /* * I2S DAC */ #define I2S_DOUT 27 // DIN connection #define I2S_BCLK 26 // BCLK Bit clock #define I2S_LRC 25 // WSEL Left Right Clock - /* * ENCODER */ @@ -36,9 +41,8 @@ * BUTTONS */ #define BTN_LEFT 32 -#define BTN_CENTER 12 +#define BTN_CENTER 31 #define BTN_RIGHT 33 - /* * ESP DEVBOARD */ diff --git a/yoRadio/displayDummy.cpp b/yoRadio/src/displays/displayDummy.cpp similarity index 96% rename from yoRadio/displayDummy.cpp rename to yoRadio/src/displays/displayDummy.cpp index 9883d50..eecb123 100644 --- a/yoRadio/displayDummy.cpp +++ b/yoRadio/src/displays/displayDummy.cpp @@ -1,8 +1,8 @@ #include "displayDummy.h" #include -#include "player.h" -#include "config.h" -#include "network.h" +#include "../../player.h" +#include "../../config.h" +#include "../../network.h" DisplayDummy::DisplayDummy() { @@ -161,3 +161,7 @@ void DisplayDummy::set_Cursor(int16_t x, int16_t y) { void DisplayDummy::printText(const char* txt) { } + +void DisplayDummy::loop() { + +} diff --git a/yoRadio/displayDummy.h b/yoRadio/src/displays/displayDummy.h similarity index 98% rename from yoRadio/displayDummy.h rename to yoRadio/src/displays/displayDummy.h index b0cb378..28eb46d 100644 --- a/yoRadio/displayDummy.h +++ b/yoRadio/src/displays/displayDummy.h @@ -2,7 +2,7 @@ #define displayDummy_h #include "Arduino.h" -#include "options.h" +#include "../../options.h" #define TFT_ROTATE 3 #define TFT_LINEHGHT 10 @@ -38,6 +38,7 @@ class DisplayDummy { void rssi(const char* str); void ip(const char* str); void drawPlaylist(uint16_t currentItem, char* currentItemText); + void loop(); private: uint16_t swidth, sheight; diff --git a/yoRadio/src/displays/displaySSD1306.cpp b/yoRadio/src/displays/displaySSD1306.cpp new file mode 100644 index 0000000..2f3f2bb --- /dev/null +++ b/yoRadio/src/displays/displaySSD1306.cpp @@ -0,0 +1,294 @@ +#include "displaySSD1306.h" +#include +#include "../../player.h" +#include "../../config.h" +#include "../../network.h" + +#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 + +#define LOGO_WIDTH 21 +#define LOGO_HEIGHT 32 + +const unsigned char logo [] PROGMEM= +{ + 0x06, 0x03, 0x00, 0x0f, 0x07, 0x80, 0x1f, 0x8f, 0xc0, 0x1f, 0x8f, 0xc0, + 0x0f, 0x07, 0x80, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xff, 0x80, + 0x1f, 0xff, 0xc0, 0x1f, 0xff, 0xc0, 0x3f, 0x8f, 0xe0, 0x7e, 0x03, 0xf0, + 0x7c, 0x01, 0xf0, 0x7c, 0x01, 0xf0, 0x7f, 0xff, 0xf0, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xf8, 0xff, 0xff, 0xf8, 0x7c, 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3f, 0xc0, 0xe0, 0x3f, 0xff, 0xe0, + 0x1f, 0xff, 0xe0, 0x0f, 0xff, 0xe0, 0x03, 0xff, 0xc0, 0x00, 0xfe, 0x00 +}; + +TwoWire I2CSSD1306 = TwoWire(0); + +DisplaySSD1306::DisplaySSD1306(): Adafruit_SSD1306(128, 64, &I2CSSD1306, I2C_RST) { + +} + +char* DisplaySSD1306::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 DisplaySSD1306::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("/"); +} + +void DisplaySSD1306::initD(uint16_t &screenwidth, uint16_t &screenheight) { + I2CSSD1306.begin(I2C_SDA, I2C_SCL, 400000); + if (!begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { + Serial.println(F("SSD1306 allocation failed")); + for (;;); // Don't proceed, loop forever + } + cp437(true); + fillScreen(TFT_BG); + setRotation(TFT_ROTATE); + setTextWrap(false); + screenwidth = width(); + screenheight = height(); + swidth = screenwidth; + sheight = screenheight; +} + +void DisplaySSD1306::drawLogo() { + clearDisplay(); + drawBitmap( + (width() - LOGO_WIDTH ) / 2, + 8, + logo, LOGO_WIDTH, LOGO_HEIGHT, 1); + display(); +} + +void DisplaySSD1306::drawPlaylist(uint16_t currentItem, char* currentItemText) { + for (byte i = 0; i < PLMITEMS; i++) { + plMenu[i][0] = '\0'; + } + config.fillPlMenu(plMenu, currentItem - 2, PLMITEMS); + setTextSize(2); + int yStart = (sheight / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3; + fillRect(0, (sheight / 2 - PLMITEMHEIGHT / 2) + 1, swidth, PLMITEMHEIGHT, TFT_LOGO); + 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); + print(utf8Rus(plMenu[i], true)); + } + } +} + +void DisplaySSD1306::clearDsp() { + fillScreen(TFT_BG); +} + +void DisplaySSD1306::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); +} + +void DisplaySSD1306::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; +} + +void DisplaySSD1306::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) { + fillRect(0, texttop, swidth, textheight, bg); +} + +void DisplaySSD1306::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); + 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 DisplaySSD1306::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 DisplaySSD1306::displayHeapForDebug() { + +} + +void DisplaySSD1306::printClock(const char* timestr) { + setTextSize(2); + centerText(timestr, 34, TFT_FG, TFT_BG); + setTextSize(1); +} + +void DisplaySSD1306::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); + } +} + +void DisplaySSD1306::frameTitle(const char* str) { + setTextSize(2); + centerText(str, TFT_FRAMEWDT, TFT_LOGO, TFT_BG); +} + +void DisplaySSD1306::rssi(const char* str) { + int16_t vTop = sheight - TFT_LINEHGHT - 4; + setTextSize(1); + rightText(str, vTop, SILVER, TFT_BG); +} + +void DisplaySSD1306::ip(const char* str) { + int16_t vTop = sheight - TFT_LINEHGHT - 4; + setTextSize(1); + setTextColor(SILVER, TFT_BG); + setCursor(0, vTop); + print(str); +} + +void DisplaySSD1306::set_TextSize(uint8_t s) { + setTextSize(s); +} + +void DisplaySSD1306::set_TextColor(uint16_t fg, uint16_t bg) { + setTextColor(fg, bg); +} + +void DisplaySSD1306::set_Cursor(int16_t x, int16_t y) { + setCursor(x, y); +} + +void DisplaySSD1306::printText(const char* txt) { + print(txt); +} + +void DisplaySSD1306::loop() { + if (checkdelay(83, loopdelay)) { + display(); + } + yield(); +} + +boolean DisplaySSD1306::checkdelay(int m, unsigned long &tstamp) { + if (millis() - tstamp > m) { + tstamp = millis(); + return true; + } else { + return false; + } +} diff --git a/yoRadio/src/displays/displaySSD1306.h b/yoRadio/src/displays/displaySSD1306.h new file mode 100644 index 0000000..94cbf89 --- /dev/null +++ b/yoRadio/src/displays/displaySSD1306.h @@ -0,0 +1,60 @@ +#ifndef displayST7735_h +#define displayST7735_h + +#include "Arduino.h" +#include +#include +#include "../../options.h" + +#define TFT_ROTATE 0 +#define TFT_LINEHGHT 8 +#define TFT_FRAMEWDT 0 + +#define PLMITEMS 5 +#define PLMITEMLENGHT 40 +#define PLMITEMHEIGHT 18 + +class DisplaySSD1306: public Adafruit_SSD1306 { + public: + DisplaySSD1306(); + 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); + 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(); + private: + uint16_t swidth, sheight; + unsigned long loopdelay; + boolean checkdelay(int m, unsigned long &tstamp); +}; + +extern DisplaySSD1306 dsp; + +/* + * TFT COLORS + */ +#define SILVER WHITE +#define TFT_BG BLACK +#define TFT_FG WHITE +#define TFT_LOGO WHITE + +#endif diff --git a/yoRadio/displayST7735.cpp b/yoRadio/src/displays/displayST7735.cpp similarity index 98% rename from yoRadio/displayST7735.cpp rename to yoRadio/src/displays/displayST7735.cpp index 5d034dd..9ce3dbf 100644 --- a/yoRadio/displayST7735.cpp +++ b/yoRadio/src/displays/displayST7735.cpp @@ -1,9 +1,9 @@ #include "displayST7735.h" #include #include "fonts/bootlogo.h" -#include "player.h" -#include "config.h" -#include "network.h" +#include "../../player.h" +#include "../../config.h" +#include "../../network.h" #define DTYPE INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html /* If there is a noisy line on one side of the screen, then in Adafruit_ST7735.cpp: @@ -319,3 +319,8 @@ void DisplayST7735::set_Cursor(int16_t x, int16_t y) { void DisplayST7735::printText(const char* txt) { print(txt); } + +void DisplayST7735::loop() { + +} + diff --git a/yoRadio/displayST7735.h b/yoRadio/src/displays/displayST7735.h similarity index 98% rename from yoRadio/displayST7735.h rename to yoRadio/src/displays/displayST7735.h index 6b78865..9ee00c9 100644 --- a/yoRadio/displayST7735.h +++ b/yoRadio/src/displays/displayST7735.h @@ -4,7 +4,7 @@ #include "Arduino.h" #include #include -#include "options.h" +#include "../../options.h" #include "fonts/DS_DIGI28pt7b.h" #define TFT_ROTATE 3 @@ -41,6 +41,7 @@ class DisplayST7735: public Adafruit_ST7735 { void rssi(const char* str); void ip(const char* str); void drawPlaylist(uint16_t currentItem, char* currentItemText); + void loop(); private: uint16_t swidth, sheight; diff --git a/yoRadio/fonts/DS_DIGI28pt7b.h b/yoRadio/src/displays/fonts/DS_DIGI28pt7b.h similarity index 100% rename from yoRadio/fonts/DS_DIGI28pt7b.h rename to yoRadio/src/displays/fonts/DS_DIGI28pt7b.h diff --git a/yoRadio/fonts/bootlogo.h b/yoRadio/src/displays/fonts/bootlogo.h similarity index 100% rename from yoRadio/fonts/bootlogo.h rename to yoRadio/src/displays/fonts/bootlogo.h