diff --git a/Controls.md b/Controls.md new file mode 100644 index 0000000..47b678b --- /dev/null +++ b/Controls.md @@ -0,0 +1,68 @@ +## Controls + +
+ +--- +- [Buttons](#buttons) +- [Encoders](#encoders) +- [IR receiver](#ir-receiver) +- [Joystick](#joystic) +- [Back to Readme](Readme.md) + +--- +### Buttons +Up to 5 buttons can be connected to the device. Three buttons are enough to control it. + +Button actions: +- BTN_LEFT\ + click: volume down\ + dblclick: previous station\ + longpress: quick volume down +- BTN_CENTER\ + click: start/stop playing\ + dblclick: toggle between PLAYER/PLAYLIST mode\ + longpress: toggle between PLAYER/PLAYLIST mode +- BTN_RIGHT\ + click: volume up\ + dblclick: next station\ + longpress: quick volume up +- BTN_UP\ + click: without display - next station, with display - move up\ + dblclick: doing nothing\ + longpress: with display - quick move up +- BTN_DOWN\ + click: without display - prev station, with display - move down\ + dblclick: doing nothing\ + longpress: with display - quick move down + +--- +### Encoders +You can connect one or two encoders to replace/complete the buttons. One encoder (without buttons) is enough to control the device. + +- ENCODER1\ + rotate left: (ENC_BTNL) in PLAYER mode - volume down, in PLAYLIST mode - move up\ + rotate right: (ENC_BTNR) in PLAYER mode - volume up, in PLAYLIST mode - move down\ + click, dblclick, longpress: (ENC_BTNB) same as BTN_CENTER +- ENCODER2\ + rotate left: (ENC2_BTNL) if not pressed - switch to PLAYLIST mode and move up, if pressed - volume down\ + rotate right: (ENC2_BTNR) if not pressed - switch to PLAYLIST mode and move down, if pressed - volume up\ + click, dblclick: (ENC2_BTNB) same as BTN_CENTER + +--- +### IR receiver +- IR_CODE_PLAY: start/stop playing +- IR_CODE_PREV: previous station +- IR_CODE_NEXT: next station +- IR_CODE_VOLUP: volume up, longpress - quick volume up +- IR_CODE_VOLDN: volume down, longpress - quick volume down +- IR_CODE_HASH: toggle between PLAYER/PLAYLIST mode +- IR_CODE_NUM0-NUM9:\ + Start entering the station number. To finish input and start playback, press the play button. To cancel, press hash. + +--- +### Joystick +You can use a joystick [like this](https://aliexpress.com/item/4000681560472.html) instead of connecting five buttons + +
+ +--- diff --git a/Images.md b/Images.md index ff8b99a..89d7843 100644 --- a/Images.md +++ b/Images.md @@ -25,4 +25,8 @@ \ ![ёRadio](images/img11.jpg)\ \ -![ёRadio](images/img12.jpg) +![ёRadio](images/img12.jpg)\ +\ +![ёRadio](images/img13.jpg)\ +\ +![ёRadio](images/img14.jpg) diff --git a/README.md b/README.md index a003605..f0b1f88 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [Hardware setup](#hardware-setup) - [Quick start](#quick-start) - [Update](#update) +- [Controls](Controls.md) - [MQTT](#mqtt) - [Home Assistant](#home-assistant) - [More features](#more-features) @@ -230,7 +231,7 @@ download _http://\/data/playlist.csv_ and _http://\/data **Commands**: \ **prev** - prev station \ **next** - next station \ - **toggle** - start/stop playing \ + **toggle** - start/stop playing \ **stop** - stop playing \ **start, play** - start playing \ **boot, reboot** - reboot \ @@ -243,6 +244,13 @@ download _http://\/data/playlist.csv_ and _http://\/data --- ## Version history +#### v0.5.033 +- added two buttons BTN_UP, BTN_DOWN +- added the pins for the second encoder ENC2_BTNL, ENC2_BTNB, ENC2_BTNR +- fixed display of playlist with SSD1306 configuration +- improvements in the displays work +- bugs fixes, some improvements + #### v0.5.020 - added support for SSD1306 128x32 I2C displays diff --git a/exsamples/myoptions.h b/exsamples/myoptions.h index 60d4876..cedba12 100644 --- a/exsamples/myoptions.h +++ b/exsamples/myoptions.h @@ -49,6 +49,14 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti //#define ENC_HALFQUARD true /* Experiment with it */ /******************************************/ +/* ENCODER2 */ +//#define ENC2_BTNL 255 /* Left rotation */ +//#define ENC2_BTNB 255 /* Encoder button */ +//#define ENC2_BTNR 255 /* Right rotation */ +//#define ENC2_INTERNALPULLUP true /* Enable the weak pull up resistors */ +//#define ENC2_HALFQUARD true /* Experiment with it */ +/******************************************/ + /* BUTTONS */ //#define BTN_LEFT 255 /* VolDown, Prev */ //#define BTN_CENTER 255 /* Play, Stop, Show playlist */ diff --git a/images/controls.jpg b/images/controls.jpg new file mode 100644 index 0000000..f154a74 Binary files /dev/null and b/images/controls.jpg differ diff --git a/images/img13.jpg b/images/img13.jpg index 1bac5ab..d4923a2 100644 Binary files a/images/img13.jpg and b/images/img13.jpg differ diff --git a/images/img14.jpg b/images/img14.jpg new file mode 100644 index 0000000..fa042d2 Binary files /dev/null and b/images/img14.jpg differ diff --git a/images/joystick.jpg b/images/joystick.jpg new file mode 100644 index 0000000..45e3e70 Binary files /dev/null and b/images/joystick.jpg differ diff --git a/yoRadio/controls.cpp b/yoRadio/controls.cpp index 41b8ea9..40650f4 100644 --- a/yoRadio/controls.cpp +++ b/yoRadio/controls.cpp @@ -6,19 +6,25 @@ #include "display.h" long encOldPosition = 0; +long enc2OldPosition = 0; int lpId = -1; -#define ISPUSHBUTTONS BTN_LEFT!=255 || BTN_LEFT!=255 || BTN_RIGHT!=255 || ENC_BTNB!=255 +#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}}; +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_BTNL!=255 && ENC_BTNR!=255 +#if (ENC_BTNL!=255 && ENC_BTNR!=255) || (ENC2_BTNL!=255 && ENC2_BTNR!=255) #include +#if (ENC_BTNL!=255 && ENC_BTNR!=255) ESP32Encoder encoder; #endif +#if (ENC2_BTNL!=255 && ENC2_BTNR!=255) +ESP32Encoder encoder2; +#endif +#endif #if IR_PIN!=255 #include @@ -41,17 +47,25 @@ decode_results irResults; void initControls() { #if ENC_BTNL!=255 - ESP32Encoder::useInternalWeakPullResistors = ENC_INTERNALPULLUP ? UP : DOWN; + encoder.useInternalWeakPullResistors = ENC_INTERNALPULLUP ? UP : DOWN; if (ENC_HALFQUARD) { encoder.attachHalfQuad(ENC_BTNL, ENC_BTNR); } else { encoder.attachFullQuad(ENC_BTNL, ENC_BTNR); } #endif +#if ENC2_BTNL!=255 + encoder2.useInternalWeakPullResistors = ENC2_INTERNALPULLUP ? UP : DOWN; + if (ENC2_HALFQUARD) { + encoder2.attachHalfQuad(ENC2_BTNL, ENC2_BTNR); + } else { + encoder2.attachFullQuad(ENC2_BTNL, ENC2_BTNR); + } +#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)) continue; + 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); @@ -84,14 +98,20 @@ void loopControls() { #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)) continue; + 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 @@ -111,6 +131,22 @@ void encoderLoop() { } #endif +#if ENC2_BTNL!=255 +void encoder2Loop() { + long encNewPosition = encoder2.getCount() / 2; + if (encNewPosition != 0 && encNewPosition != enc2OldPosition) { + enc2OldPosition = encNewPosition; + encoder2.setCount(0); + uint8_t bp = 2; + if(ENC2_BTNB!=255){ + bp = digitalRead(ENC2_BTNB); + } + if(bp==HIGH && display.mode!=STATIONS) display.swichMode(STATIONS); + controlsEvent(encNewPosition > 0); + } +} +#endif + #if IR_PIN!=255 void irBlink() { if (player.mode == STOPPED) { @@ -183,6 +219,7 @@ void irLoop() { } case IR_CODE_HASH: { if (display.mode == NUMBERS) { + display.returnTile(); display.swichMode(PLAYER); display.numOfNextStation = 0; break; @@ -236,14 +273,16 @@ void irLoop() { #endif // if IR_PIN!=255 void onBtnLongPressStart(int id) { - switch (id) { - case 0: - case 2: { + switch ((controlEvt_e)id) { + case EVT_BTNLEFT: + case EVT_BTNRIGHT: + case EVT_BTNUP: + case EVT_BTNDOWN:{ lpId = id; break; } - case 1: - case 3: { + case EVT_BTNCENTER: + case EVT_ENCBTNB: { display.swichMode(display.mode == PLAYER ? STATIONS : PLAYER); break; } @@ -251,9 +290,11 @@ void onBtnLongPressStart(int id) { } void onBtnLongPressStop(int id) { - switch (id) { - case 0: - case 2: { + switch ((controlEvt_e)id) { + case EVT_BTNLEFT: + case EVT_BTNRIGHT: + case EVT_BTNUP: + case EVT_BTNDOWN:{ lpId = -1; break; } @@ -272,15 +313,25 @@ boolean checklpdelay(int m, unsigned long &tstamp) { void onBtnDuringLongPress(int id) { if (checklpdelay(BTN_LONGPRESS_LOOP_DELAY, lpdelay)) { - switch (id) { - case 0: { + switch ((controlEvt_e)id) { + case EVT_BTNLEFT: { controlsEvent(false); break; } - case 2: { + case EVT_BTNRIGHT: { controlsEvent(true); break; } + case EVT_BTNUP: + case EVT_BTNDOWN: { + if (display.mode == PLAYER) { + display.swichMode(STATIONS); + } + if (display.mode == STATIONS) { + controlsEvent(id==EVT_BTNDOWN); + } + break; + } } } } @@ -305,13 +356,14 @@ void controlsEvent(bool toRight) { } void onBtnClick(int id) { - switch (id) { - case 0: { + switch ((controlEvt_e)id) { + case EVT_BTNLEFT: { controlsEvent(false); break; } - case 1: - case 3: { + case EVT_BTNCENTER: + case EVT_ENCBTNB: + case EVT_ENC2BTNB: { if (display.mode == NUMBERS) { display.numOfNextStation = 0; display.swichMode(PLAYER); @@ -325,26 +377,45 @@ void onBtnClick(int id) { } break; } - case 2: { + 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.swichMode(STATIONS); + } + if (display.mode == STATIONS) { + controlsEvent(id==EVT_BTNDOWN); + } + } + break; + } } } void onBtnDoubleClick(int id) { - switch (id) { - case 0: { + switch ((controlEvt_e)id) { + case EVT_BTNLEFT: { if (display.mode != PLAYER) return; player.prev(); break; } - case 1: - case 3: { + case EVT_BTNCENTER: + case EVT_ENCBTNB: + case EVT_ENC2BTNB: { display.swichMode(display.mode == PLAYER ? STATIONS : PLAYER); break; } - case 2: { + case EVT_BTNRIGHT: { if (display.mode != PLAYER) return; player.next(); break; diff --git a/yoRadio/controls.h b/yoRadio/controls.h index 0d15e67..7963c3f 100644 --- a/yoRadio/controls.h +++ b/yoRadio/controls.h @@ -1,11 +1,14 @@ #ifndef controls_h #define controls_h +enum controlEvt_e { EVT_BTNLEFT, EVT_BTNCENTER, EVT_BTNRIGHT, EVT_ENCBTNB, EVT_BTNUP, EVT_BTNDOWN, EVT_ENC2BTNB }; + boolean checklpdelay(int m, unsigned long &tstamp); void initControls(); void loopControls(); void encoderLoop(); +void encoder2Loop(); void irLoop(); void irNum(byte num); void irBlink(); diff --git a/yoRadio/display.cpp b/yoRadio/display.cpp index 30f87c7..5201ffe 100644 --- a/yoRadio/display.cpp +++ b/yoRadio/display.cpp @@ -260,7 +260,9 @@ void Display::swichMode(displayMode_e newmode) { volume(); #endif } else { - meta.lock(); + if (newmode != NUMBERS) { + meta.lock(); + } title1.lock(); if (TITLE_SIZE2 != 0) title2.lock(); #ifdef CLOCK_SPACE @@ -271,7 +273,8 @@ void Display::swichMode(displayMode_e newmode) { dsp.frameTitle("VOLUME"); } if (newmode == NUMBERS) { - dsp.frameTitle("STATION"); + //dsp.frameTitle("STATION"); + meta.reset(); } if (newmode == STATIONS) { currentPlItem = config.store.lastStation; @@ -305,6 +308,11 @@ void Display::drawPlaylist() { } void Display::drawNextStationNum(uint16_t num) { + char plMenu[1][40]; + char currentItemText[40] = {0}; + config.fillPlMenu(plMenu, num, 1); + strlcpy(currentItemText, plMenu[0], 39); + meta.setText(dsp.utf8Rus(currentItemText, true)); dsp.drawNextStationNum(num); } @@ -319,6 +327,7 @@ void Display::loop() { break; } case NUMBERS: { + meta.loop(); break; } case STATIONS: { @@ -354,6 +363,12 @@ void Display::station() { netserver.requestOnChange(STATION, 0); } +void Display::returnTile(){ + meta.setText(dsp.utf8Rus(config.station.name, true)); + meta.reset(); + dsp.loop(); +} + void Display::title(const char *str) { const char *title = str; char ttl[BUFLEN / 2] = { 0 }; diff --git a/yoRadio/display.h b/yoRadio/display.h index 67e3580..ab3970d 100644 --- a/yoRadio/display.h +++ b/yoRadio/display.h @@ -55,6 +55,7 @@ class Display { void bootLogo(); void station(); void title(const char *str); + void returnTile(); void time(bool redraw = false); void volume(); void ip(); diff --git a/yoRadio/options.h b/yoRadio/options.h index 8aa5ec4..4ad7a46 100644 --- a/yoRadio/options.h +++ b/yoRadio/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define VERSION "0.5.020" +#define VERSION "0.5.035" /******************************************************* DO NOT EDIT THIS FILE. @@ -96,6 +96,22 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti #define ENC_HALFQUARD true #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 true +#endif + /* BUTTONS */ #ifndef BTN_LEFT #define BTN_LEFT 255 @@ -106,6 +122,12 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti #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 diff --git a/yoRadio/src/LiquidCrystalI2C/LiquidCrystalI2CEx.cpp b/yoRadio/src/LiquidCrystalI2C/LiquidCrystalI2CEx.cpp index 6a5a091..1699b2c 100644 --- a/yoRadio/src/LiquidCrystalI2C/LiquidCrystalI2CEx.cpp +++ b/yoRadio/src/LiquidCrystalI2C/LiquidCrystalI2CEx.cpp @@ -64,7 +64,7 @@ void LiquidCrystal_I2C::init_priv() if((_sda_pin==255 && _scl_pin==255) || (_sda_pin==21 && _scl_pin==22)){ Wire.begin(); }else{ - Wire.begin(_sda_pin, _scl_pin, (uint32_t)100000); + Wire.begin((int)_sda_pin, (int)_scl_pin, (uint32_t)100000); } _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; begin(_cols, _rows); diff --git a/yoRadio/src/displays/displayLC1602.cpp b/yoRadio/src/displays/displayLC1602.cpp index ad72d2b..1b3856d 100644 --- a/yoRadio/src/displays/displayLC1602.cpp +++ b/yoRadio/src/displays/displayLC1602.cpp @@ -64,7 +64,7 @@ void DisplayLC1602::getScrolBbounds(const char* text, const char* separator, byt } void DisplayLC1602::clearScroll(uint16_t texttop, uint16_t textheight, uint16_t bg) { - for(uint16_t x=0; x