// Learn about the ESP32 WiFi simulation in
// https://docs.wokwi.com/guides/esp32-wifi
#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32RotaryEncoder.h>
#define ENCODER_PIN_1 12
#define ENCODER_PIN_2 14
#define ENCODER_SW_PIN 27
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
char lcdBuffer[2][17];
//RotaryEncoder encoder(ENCODER_PIN_1, ENCODER_PIN_1, RotaryEncoder::LatchMode::TWO03);
RotaryEncoder rotaryEncoder( ENCODER_PIN_1, ENCODER_PIN_2, ENCODER_SW_PIN );
long
lastEncoderReadTime = 0,
lastFrameUpdate = 0;
int
lastEncoderPos = 0,
frameCounter = 1;
TaskHandle_t
lcdTask;
class Menu {
private:
const char
selectorChar;
const size_t
menuSize = 0,
outBufferRows = 2,
outBufferCols = 17;
int
cursorPos = 0,
scrollPos = 0;
char *menuItems;
static int limit(int *value, int minValue, int maxValue) {
int diff = 0;
if(*value < minValue) {
diff = *value - minValue;
*value = minValue;
}
else if(*value > maxValue) {
diff = *value - maxValue;
*value = maxValue;
}
return diff;
}
public:
Menu(char *items, size_t menuSize, size_t outCols, size_t outRows, char selector = '>' ) :
selectorChar(selector),
menuItems(items),
menuSize(menuSize),
outBufferCols(outCols),
outBufferRows(outRows)
{ }
void scroll(int delta) {
cursorPos += delta;
scrollPos += limit(&cursorPos, 0, outBufferRows - 1);
limit(&scrollPos, 0, menuSize - outBufferRows);
}
int getSelectedItem() {
return cursorPos + scrollPos;
}
void draw(char *buffer) {
for(size_t i = 0; i < outBufferRows; i++) {
sprintf(buffer + i * outBufferCols, "%c%s", cursorPos == i ? selectorChar : ' ', menuItems + (scrollPos + i) * (outBufferCols - 1));
}
}
};
char menuItems[][16] = {
"Aktuell: 0.0l",
"Fass tauschen ",
"Waage tarieren ",
" \177 back "
};
Menu testMenu(&menuItems[0][0], sizeof(menuItems) / sizeof(menuItems[0]), sizeof(menuItems[0]) + 1, 2, '+');
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
rotaryEncoder.setBoundaries(-9999, 9999, 0);
rotaryEncoder.setEncoderType( EncoderType::HAS_PULLUP );
rotaryEncoder.onTurned( &knobCallback );
rotaryEncoder.onPressed( &buttonCallback );
rotaryEncoder.begin();
xTaskCreatePinnedToCore(LcdTask, "LcdTask", 4096, NULL, 1, &lcdTask, 0);
}
int test = 0;
void loop() {
int encoderDelta = 0;
if(lastEncoderReadTime + 50 < millis()) {
int currentEncoderPos = rotaryEncoder.getEncoderValue();
encoderDelta = currentEncoderPos - lastEncoderPos;
lastEncoderPos = currentEncoderPos;
lastEncoderReadTime = millis();
sprintf(menuItems[0], "Menu Item 1 %d", ++test % 100);
testMenu.scroll(encoderDelta);
testMenu.draw(&lcdBuffer[0][0]);
Serial.print("Selected: ");
Serial.println(testMenu.getSelectedItem());
//DrawMenu(encoderDelta);
}
if(lastFrameUpdate + 50 < millis()) {
//if(encoderDelta != 0) {
//DrawMenu(encoderDelta);
//}
lastFrameUpdate = millis();
}
}
/*
void DrawMenu(int encoderDelta) {
static int
cursorPos = 0,
scrollPos = 0;
cursorPos += encoderDelta;
scrollPos += limit(&cursorPos, 0, 1);
limit(&scrollPos, 0, 2);
sprintf(lcdBuffer[0], menuItems[scrollPos], cursorPos == 0 ? '>' : ' ');
sprintf(lcdBuffer[1], menuItems[scrollPos + 1], cursorPos == 1 ? '>' : ' ');
}*/
int limit(int *value, int minValue, int maxValue) {
int diff = 0;
if(*value < minValue) {
diff = *value - minValue;
*value = minValue;
}
else if(*value > maxValue) {
diff = *value - maxValue;
*value = maxValue;
}
return diff;
}
void knobCallback( long value )
{
}
void buttonCallback( unsigned long duration )
{
}
void LcdTask(void * parameter) {
while(true)
{
lcd.setCursor(0, 0);
lcd.print(lcdBuffer[0]);
lcd.setCursor(0, 1);
lcd.print(lcdBuffer[1]);
if(++frameCounter > 100) {
frameCounter = 1;
}
delay(50);
yield();
}
}