#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// ===== Display Pins =====
#define TFT_DC 4
#define TFT_CS 5
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
// ===== Buttons =====
const int BTN_RED_PIN = 32;
const int BTN_GREEN_PIN = 33;
const int BTN_BLUE_PIN = 27;
// ===== Farben =====
static inline uint16_t RGB565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
const uint16_t COLOR_ORANGE = RGB565(255,165,0);
const uint16_t COLOR_DARKGREY = RGB565(60,60,60);
const uint16_t COLOR_LIGHTGREY = RGB565(200,200,200);
// ===== Screens =====
enum ScreenId { SCREEN_WELCOME, SCREEN_READY, SCREEN_STATUS };
ScreenId currentScreen = SCREEN_WELCOME;
ScreenId lastScreen = (ScreenId)(-1);
// ===== Globals =====
int16_t tftW, tftH;
bool lastRed = HIGH, lastGreen = HIGH, lastBlue = HIGH;
uint32_t lastChangeRed = 0, lastChangeGreen = 0, lastChangeBlue = 0;
const uint16_t DEBOUNCE_MS = 20;
// Balkenwerte
int fuelLevel = 85;
int oilTemp = 72;
int oilPress = 45;
int hydrPress = 88;
uint32_t lastUpdate = 0;
// ===== Hilfsfunktionen =====
int16_t textWidthPx(const char* s, uint8_t size) {
return strlen(s) * 6 * size;
}
void drawCenteredText(const char* s, int16_t cx, int16_t y, uint16_t color, uint8_t size) {
int16_t w = textWidthPx(s, size);
tft.setCursor(cx - w/2, y);
tft.setTextColor(color);
tft.setTextSize(size);
tft.print(s);
}
// Bottom Button Legend (normale Funktion statt Lambda)
void drawLegendButton(int16_t cx, int16_t yBar, int16_t barH, uint16_t color, const char* lbl) {
const int16_t bw = 60, bh = 22, r = 6;
int16_t x = cx - bw/2;
int16_t y = yBar + (barH - bh)/2;
tft.fillRoundRect(x, y, bw, bh, r, color);
tft.drawRoundRect(x, y, bw, bh, r, COLOR_LIGHTGREY);
drawCenteredText(lbl ? lbl : "", cx, y + 6, ILI9341_WHITE, 1);
}
void drawBottomButtonLegend(const char* left, const char* mid, const char* right) {
const int16_t barH = 34;
const int16_t yBar = tftH - barH;
tft.fillRect(0, yBar, tftW, barH, RGB565(20,20,20));
int16_t cxL = tftW/6, cxM = tftW/2, cxR = tftW*5/6;
drawLegendButton(cxL, yBar, barH, ILI9341_RED, left);
drawLegendButton(cxM, yBar, barH, ILI9341_GREEN, mid);
drawLegendButton(cxR, yBar, barH, ILI9341_BLUE, right);
}
// Balken zeichnen
void drawBar(int16_t x,int16_t y,int16_t w,int16_t h,int value,int maxVal,uint16_t color,const char* label){
tft.drawRect(x,y,w,h,COLOR_LIGHTGREY);
int fillW = map(value,0,maxVal,0,w);
tft.fillRect(x+1,y+1,fillW-2,h-2,color);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.setCursor(x,y-12);
tft.print(label);
tft.setCursor(x+w+6,y+(h/2)-4);
tft.print(value);
}
// ===== Screens =====
void renderWelcomeScreen() {
tft.fillScreen(ILI9341_BLACK);
int16_t cx = tftW/2;
drawCenteredText("Welcome Pilot", cx, 30, ILI9341_WHITE, 3);
drawCenteredText("on Jet FA 18", cx, 70, ILI9341_YELLOW, 3);
tft.fillRoundRect(cx-120,150-30,240,60,10,COLOR_DARKGREY);
tft.drawRoundRect(cx-120,150-30,240,60,10,COLOR_ORANGE);
drawCenteredText("Start Engine", cx, 150-8, ILI9341_WHITE, 2);
drawCenteredText("Press GREEN to start", cx, 220, COLOR_LIGHTGREY, 1);
drawBottomButtonLegend("Back","Start","Menu");
}
void renderReadyScreen() {
tft.fillScreen(ILI9341_BLACK);
int16_t cx = tftW/2;
drawCenteredText("Menu", cx, 40, ILI9341_CYAN, 3);
drawCenteredText("Ready for Take Off", cx, 90, ILI9341_GREEN, 3);
drawCenteredText("System checks: OK", cx, 140, ILI9341_WHITE, 2);
drawCenteredText("Fuel: 100%", cx, 170, ILI9341_WHITE, 2);
drawBottomButtonLegend("Back","Continue","Status");
}
void renderStatusScreen() {
tft.fillScreen(ILI9341_BLACK);
int16_t cx = tftW/2;
drawCenteredText("Engine Status", cx, 20, ILI9341_CYAN, 3);
int16_t startX=20,startY=70,barW=180,barH=18,gapY=40;
drawBar(startX,startY,barW,barH,fuelLevel,100,ILI9341_GREEN,"Fuel");
drawBar(startX,startY+gapY,barW,barH,oilTemp,120,ILI9341_YELLOW,"Oil Temp");
drawBar(startX,startY+2*gapY,barW,barH,oilPress,100,ILI9341_BLUE,"Oil Press");
drawBar(startX,startY+3*gapY,barW,barH,hydrPress,100,COLOR_ORANGE,"Hydraulic");
drawBottomButtonLegend("Back","","");
}
// ===== Navigation =====
// Neu:
void switchTo(uint8_t next){ currentScreen = (ScreenId)next; }
bool buttonPressedEdge(int pin,bool &last,uint32_t &ts){
bool raw=digitalRead(pin);uint32_t now=millis();
if(raw!=last && (now-ts)<DEBOUNCE_MS)return false;
if(raw!=last){ts=now;bool wasHigh=last;last=raw;if(wasHigh&&raw==LOW)return true;}
return false;
}
void pollButtonsAndAct(){
if(buttonPressedEdge(BTN_RED_PIN,lastRed,lastChangeRed)){
if(currentScreen==SCREEN_STATUS)switchTo(SCREEN_READY);
}
if(buttonPressedEdge(BTN_GREEN_PIN,lastGreen,lastChangeGreen)){
if(currentScreen==SCREEN_WELCOME)switchTo(SCREEN_READY);
}
if(buttonPressedEdge(BTN_BLUE_PIN,lastBlue,lastChangeBlue)){
if(currentScreen==SCREEN_READY)switchTo(SCREEN_STATUS);
}
}
// ===== Setup & Loop =====
void setup(){
tft.begin();tft.setRotation(1);
tftW=tft.width();tftH=tft.height();
pinMode(BTN_RED_PIN,INPUT_PULLUP);
pinMode(BTN_GREEN_PIN,INPUT_PULLUP);
pinMode(BTN_BLUE_PIN,INPUT_PULLUP);
switchTo(SCREEN_WELCOME);
}
void loop(){
if(currentScreen!=lastScreen){
if(currentScreen==SCREEN_WELCOME)renderWelcomeScreen();
else if(currentScreen==SCREEN_READY)renderReadyScreen();
else if(currentScreen==SCREEN_STATUS)renderStatusScreen();
lastScreen=currentScreen;
}
pollButtonsAndAct();
// Balkenwerte alle 2 Sekunden aktualisieren
if(currentScreen==SCREEN_STATUS && millis()-lastUpdate>2000){
fuelLevel= fuelLevel - random(1,3);
oilTemp=random(60,120);
oilPress=random(60,65);
hydrPress=random(70,80);
renderStatusScreen();
lastUpdate=millis();
}
delay(5);
}