/*
Simple "Hello World" for ILI9341 LCD
https://wokwi.com/arduino/projects/308024602434470466
*/
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "SPI.h"
#define TFT_DC 9
#define TFT_CS 10
#define UBUT 2
#define RBUT 3
#define DBUT 4
#define LBUT 5
#define UNKNOWN_BUT 5
#define SCREEN_HEIGHT 320
#define SCREEN_WIDTH 240
#define MENU_TXT_SIZE 3
#define MENU_LN_SPACING 10
#define PATH_TEXT_SIZE 2
#define PATH_LINE_SPACING 3
#define PATH_LINE_HEIGHT 5
#define PATH_HEIGHT PATH_TEXT_SIZE * 10 + PATH_LINE_SPACING + PATH_LINE_HEIGHT
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
byte menuDepth = 0;
byte menuCursor = 0;
byte menuPos[6] = {0, 0, 0, 0, 0, 255};
typedef struct menuEntry_s {
char name[20];
struct menuEntry_s *subMenus;
byte nbSubMenu;
void (*menuFunction)(void);
} menuEntry_t;
menuEntry_t mainSub[3] = {{"Magstripe", nullptr, 0, nullptr}, {"RFID", nullptr, 0, nullptr}, {"NFC", nullptr, 0, nullptr}};
menuEntry_t mainMenu = {"Main menu", mainSub, 3, nullptr};
void clearScreen(void) {
tft.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
}
void setup() {
tft.begin();
tft.setRotation(0);
pinMode(LBUT, INPUT_PULLUP);
pinMode(RBUT, INPUT_PULLUP);
pinMode(DBUT, INPUT_PULLUP);
pinMode(UBUT, INPUT_PULLUP);
}
byte waitButtonPress(void) {
while (digitalRead(UBUT) == HIGH && digitalRead(RBUT) == HIGH && digitalRead(DBUT) == HIGH && digitalRead(LBUT) == HIGH)
;
if (digitalRead(UBUT) == LOW)
return UBUT;
if (digitalRead(RBUT) == LOW)
return RBUT;
if (digitalRead(DBUT) == LOW)
return DBUT;
if (digitalRead(LBUT) == LOW)
return LBUT;
return UNKNOWN_BUT;
}
menuEntry_t *getCurrentMenu(void) {
menuEntry_t *m = &mainMenu;
for (int i = 0; i < menuDepth; ++i) {
m = &m->subMenus[menuPos[i]];
}
return m;
}
void navigateButton(menuEntry_t *m, byte b) {
if (b == UBUT) {
if (menuCursor > 0)
--menuCursor;
} else if (b == RBUT) {
if (m->nbSubMenu == 0)
return;
menuPos[menuDepth++] = menuCursor;
menuCursor = 0;
} else if (b == DBUT) {
if (menuCursor + 1 < m->nbSubMenu)
++menuCursor;
} else if (b == LBUT) {
if (menuDepth == 0)
return;
menuCursor = menuPos[--menuDepth];
} else {
return;
}
}
void displayText(uint16_t x, uint16_t y, uint16_t color, uint16_t backgndColor, uint8_t size, char *txt) {
tft.setCursor(x, y);
tft.setTextColor(color, backgndColor);
tft.setTextSize(size);
tft.println(txt);
}
void displayPath(menuEntry_t *m) {
for (int i = PATH_TEXT_SIZE * 10 + PATH_LINE_SPACING; i < PATH_HEIGHT; ++i)
tft.drawLine(0, i, SCREEN_WIDTH, i, 0x07FF);
displayText(5, 5, 0x07FF, 0x0000, PATH_TEXT_SIZE, m->name);
}
void displayMenu(menuEntry_t *m) {
int y = PATH_HEIGHT + MENU_LN_SPACING;
for (int i = 0; i < 6; ++i)
Serial.println(menuPos[i]);
Serial.println("\r\n");
for (int i = 0; i < m->nbSubMenu; ++i) {
if (menuCursor == i)
displayText(5, y, 0x0000, 0x07FF, MENU_TXT_SIZE, m->subMenus[i].name);
else
displayText(5, y, 0x07FF, 0x0000, MENU_TXT_SIZE, m->subMenus[i].name);
y += MENU_LN_SPACING + MENU_TXT_SIZE * 10;
}
}
void navigateMenus() {
menuEntry_t *m = nullptr;
m = getCurrentMenu();
clearScreen();
displayPath(m);
displayMenu(m);
navigateButton(m, waitButtonPress());
}
void loop() {
navigateMenus();
}