#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
// #include "fonts/Pixel_Operator.c"
U8G2_SSD1306_128X64_NONAME_F_HW_I2C display(U8G2_R0, /* reset=*/U8X8_PIN_NONE); // initialization for the used OLED display
struct MenuOffset
{
int id;
int offset;
int size;
};
struct MenuItem
{
const char *title;
const int subMenuIdx;
};
struct MenuItem HOME_MENU[] = {
{"Display", 1},
{"Sound", 2},
{"Connection", 3},
{"About", 0},
{"Exit", 0},
};
struct MenuItem DISP_MENU[] = {
{"Brightness", 0},
{"Contrast", 0},
{"Sleep Time", 0},
{"Screen Saver", 0}};
struct MenuItem SND_MENU[] = {
{"Profile", 0},
{"Boost", 0},
{"Dlg Enhance", 0},
{"Bass Boost", 0},
};
struct MenuItem CONN_MENU[] = {
{"BT Name", 0},
{"BT Switch", 0},
{"Wi-Fi Switch", 0},
};
const uint8_t *ALL_MENU[] = {
reinterpret_cast<uint8_t *>(&HOME_MENU),
reinterpret_cast<uint8_t *>(&DISP_MENU),
reinterpret_cast<uint8_t *>(&SND_MENU),
reinterpret_cast<uint8_t *>(&CONN_MENU),
};
const unsigned int ALL_MENU_SIZE[] = {
sizeof(HOME_MENU) / sizeof(HOME_MENU[0]),
sizeof(DISP_MENU) / sizeof(DISP_MENU[0]),
sizeof(SND_MENU) / sizeof(SND_MENU[0]),
sizeof(CONN_MENU) / sizeof(CONN_MENU[0]),
};
const int BTN_U = 2;
const int BTN_D = 3;
const int BTN_O = 4;
const int LCD_H = 64;
const int LCD_W = 128;
int currMenuIdx;
int pos;
bool debounce(int time, unsigned long *lastInterrupt)
{
if ((*lastInterrupt) == 0)
{
(*lastInterrupt) = millis();
return true;
}
unsigned long now = millis();
bool isDebounced = (now - (*lastInterrupt)) > time;
if (isDebounced)
*lastInterrupt = now;
return isDebounced;
}
void drawMenuText(int pos, const MenuItem *menuText, int menuSize)
{
int currPos = pos - 1;
for (int y = 14; y < LCD_H; y += 21)
{
if (currPos - pos == 0)
display.setFont(u8g2_font_tenthinnerguys_tr);
else
display.setFont(u8g2_font_glasstown_nbp_tr);
if (currPos >= 0 && currPos < menuSize)
display.drawStr(30, y, (menuText + currPos)->title);
++currPos;
}
}
void drawMenuGraphics(int pos, int menuSize)
{
const int scrollWidth = 4;
int scrollHeight = LCD_H / menuSize + 1;
int scrollPos = scrollHeight * pos;
if (scrollPos > LCD_H)
scrollPos = LCD_H;
// draw selection frame
display.drawRFrame(2, 20, 120, 20, 3);
display.drawHLine(5, 40, 115);
display.drawVLine(120, 22, 17);
// draw scrollbar
display.drawFrame(LCD_W - scrollWidth, 0, scrollWidth, LCD_H);
display.drawBox(LCD_W - scrollWidth + 1, scrollPos + 1, scrollWidth - 2, scrollHeight);
}
void setup(void)
{
currMenuIdx = 0;
Serial.begin(9600);
display.begin(); // start the u8g2 library
pinMode(BTN_O, INPUT_PULLUP);
pinMode(BTN_U, INPUT_PULLUP);
pinMode(BTN_D, INPUT_PULLUP);
}
void loop(void)
{
static unsigned long lastLcdInterrupt;
static unsigned long lastBtnInterrupt;
static unsigned long lastLogInterrupt;
const int menuSize = ALL_MENU_SIZE[currMenuIdx];
uint8_t currMenuAddr = *ALL_MENU[currMenuIdx];
MenuItem *currMenu = reinterpret_cast<MenuItem *>(currMenuAddr);
char *logText;
if (debounce(1000, &lastLogInterrupt))
{
sprintf(logText, "currMenuIdx: %d; currMenuAddr: %d; pos: %d; title: %s;",
currMenuIdx, currMenuAddr, pos, (currMenu + pos)->title);
Serial.println(logText);
}
if (digitalRead(BTN_U) == LOW)
{
if (debounce(150, &lastBtnInterrupt))
{
pos -= pos > 0 ? 1 : 0;
}
}
if (digitalRead(BTN_D) == LOW)
{
if (debounce(150, &lastBtnInterrupt))
{
pos += pos < (menuSize - 1) ? 1 : 0;
}
}
if (digitalRead(BTN_O) == LOW)
{
if (debounce(150, &lastBtnInterrupt))
{
currMenuIdx = (currMenu + pos)->subMenuIdx;
}
}
if (debounce(16, &lastLcdInterrupt))
{
display.clearBuffer();
drawMenuText(pos, currMenu, menuSize);
drawMenuGraphics(pos, menuSize);
display.sendBuffer();
}
}