#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h> // Needed for display
#include <Adafruit_ILI9341.h>
#include <FS.h>
#include <SD.h>
#define TFT_CS 10
#define TFT_DC 2
// SD Card configuration
#define SD_CS 9
// Button matrix pin definitions
#define COL1 16
#define COL2 17
#define ROW1 45
#define ROW2 48
// Define button actions
enum ButtonAction {
NONE,
UP,
DOWN,
SELECT,
BACK
};
// TFT and SD card initialization
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Variables for file navigation
File currentFile;
String fileList[10]; // Holds up to 10 file names
int fileCount = 0;
int selectedIndex = 0;
bool viewingFile = false;
void setup() {
Serial.begin(115200);
Serial.println("Initializing...");
// Set up button matrix pins
pinMode(COL1, OUTPUT);
pinMode(COL2, OUTPUT);
pinMode(ROW1, INPUT_PULLUP);
pinMode(ROW2, INPUT_PULLUP);
// Initialize TFT
tft.begin();
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
// Initialize SD card
if (!SD.begin(SD_CS)) {
tft.println("SD init failed!");
return;
}
// List files on SD card
listFiles("/");
}
void loop() {
ButtonAction action = readButtonMatrix();
if (!viewingFile) {
// Navigation mode
handleNavigation(action);
} else {
// Viewing file mode
if (action == BACK) {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
viewingFile = false;
displayFileList();
}
}
}
// Function to list files in a directory
void listFiles(const char *dirname) {
File root = SD.open(dirname);
if (!root) {
tft.println("Failed to open dir");
return;
}
fileCount = 0;
File file = root.openNextFile();
while (file && fileCount < 10) {
if (!file.isDirectory() && String(file.name()).endsWith(".txt")) {
fileList[fileCount++] = String(file.name());
}
file.close();
file = root.openNextFile();
}
displayFileList();
}
// Function to display file list on TFT
void displayFileList() {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
for (int i = 0; i < fileCount; i++) {
if (i == selectedIndex) {
tft.print("> ");
} else {
tft.print(" ");
}
tft.println(fileList[i]);
}
}
// Function to handle navigation
void handleNavigation(ButtonAction action) {
if (action == UP && selectedIndex > 0) {
selectedIndex--;
displayFileList();
} else if (action == DOWN && selectedIndex < fileCount - 1) {
selectedIndex++;
displayFileList();
} else if (action == SELECT) {
viewFile(fileList[selectedIndex]);
}
}
// Function to view the content of a file
// Function to view the content of a file
void viewFile(String filename) {
String filePath = "/" + filename; // Construct the full path
currentFile = SD.open(filePath.c_str(), FILE_READ); // Use FILE_READ mode
if (!currentFile) {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.println("Failed to open file");
return;
}
viewingFile = true;
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
// Read the file in smaller chunks to handle memory limitations
while (currentFile.available()) {
char c = currentFile.read();
tft.print(c);
// Handle display overflow by scrolling
if (tft.getCursorY() > tft.height() - 20) {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
}
}
currentFile.close();
}
// Function to read button matrix
ButtonAction readButtonMatrix() {
for (int col = 0; col < 2; col++) {
digitalWrite(COL1, col == 0 ? LOW : HIGH);
digitalWrite(COL2, col == 1 ? LOW : HIGH);
if (digitalRead(ROW1) == LOW) {
delay(200); // Debounce
return col == 0 ? UP : SELECT;
}
if (digitalRead(ROW2) == LOW) {
delay(200); // Debounce
return col == 0 ? DOWN : BACK;
}
}
return NONE;
}