diff --git a/firmware-demo/src/main.cpp b/firmware-demo/src/main.cpp index b5fa5255..c2e071e2 100644 --- a/firmware-demo/src/main.cpp +++ b/firmware-demo/src/main.cpp @@ -14,7 +14,6 @@ extern "C" { } #include -#include void setup() { lilka::begin(); @@ -130,18 +129,58 @@ void roms_menu() { } } +void sd_browser_menu(String path) { + if (!lilka::sdcard.available()) { + lilka::ui_alert("Помилка", "SD-карта не знайдена"); + return; + } + + lilka::Entry entries[32]; + int numEntries = lilka::sdcard.listDir(path, entries); + + if (numEntries == -1) { + lilka::ui_alert("Помилка", "Не вдалося прочитати директорію"); + return; + } + + String filenames[32]; + for (int i = 0; i < numEntries; i++) { + filenames[i] = entries[i].name; + } + filenames[numEntries++] = "<< Назад"; + + int cursor = 0; + while (1) { + cursor = lilka::ui_menu(String("SD: ") + path, filenames, numEntries, cursor); + if (cursor == numEntries - 1) { + return; + } + if (entries[cursor].type == lilka::EntryType::DIRECTORY) { + sd_browser_menu((path.equals("/") ? "" : path) + "/" + entries[cursor].name); + } else { + continue; + } + } +} + void loop() { String menu[] = { "Демо", "Емулятор NES", + "Браузер SD-карти", + "Про систему", }; int cursor; while (1) { - cursor = lilka::ui_menu("Головне меню", menu, 2, cursor); + cursor = lilka::ui_menu("Головне меню", menu, 4, cursor); if (cursor == 0) { demos_menu(); } else if (cursor == 1) { roms_menu(); + } else if (cursor == 2) { + sd_browser_menu("/"); + } else if (cursor == 3) { + lilka::ui_alert("Лілка", "by Андерсон\n& friends"); } } } diff --git a/lib/lilka/src/lilka.cpp b/lib/lilka/src/lilka.cpp index 5cea978b..778f9e61 100644 --- a/lib/lilka/src/lilka.cpp +++ b/lib/lilka/src/lilka.cpp @@ -6,10 +6,10 @@ namespace lilka { void begin() { serial_begin(); - display.begin(); - controller.begin(); - filesystem.begin(); + display.begin(); // Must be initialized BEFORE SD card sdcard.begin(); + controller.begin(); // Must be initialized AFTER SD card (since SD card somehow messes with GPIO) + filesystem.begin(); esp_wifi_deinit(); } diff --git a/lib/lilka/src/lilka.h b/lib/lilka/src/lilka.h index 796d9f08..587ddad3 100644 --- a/lib/lilka/src/lilka.h +++ b/lib/lilka/src/lilka.h @@ -6,6 +6,7 @@ #include "lilka/display.h" #include "lilka/filesystem.h" #include "lilka/sdcard.h" +#include "lilka/ui.h" namespace lilka { void begin(); diff --git a/lib/lilka/src/lilka/config.h b/lib/lilka/src/lilka/config.h index 90b42558..cdc2c560 100644 --- a/lib/lilka/src/lilka/config.h +++ b/lib/lilka/src/lilka/config.h @@ -7,23 +7,24 @@ # define LILKA_GPIO_UP 4 # define LILKA_GPIO_DOWN 7 -# define LILKA_GPIO_LEFT 5 -# define LILKA_GPIO_RIGHT 6 -# define LILKA_GPIO_SELECT 9 +# define LILKA_GPIO_LEFT -1 +# define LILKA_GPIO_RIGHT -1 +# define LILKA_GPIO_SELECT -1 # define LILKA_GPIO_START 10 -# define LILKA_GPIO_A 20 +# define LILKA_GPIO_A -1 # define LILKA_GPIO_B -1 +# define LILKA_SPI_SCK 0 +# define LILKA_SPI_MOSI 1 +# define LILKA_SPI_MISO 8 # define LILKA_DISPLAY_DC 3 # define LILKA_DISPLAY_CS 21 -# define LILKA_DISPLAY_SCK 0 -# define LILKA_DISPLAY_MOSI 1 # define LILKA_DISPLAY_RST 2 # define LILKA_DISPLAY_ROTATION 0 # define LILKA_DISPLAY_WIDTH 240 # define LILKA_DISPLAY_HEIGHT 280 -# define SDCARD_CS -1 +# define LILKA_SDCARD_CS 20 #elif LILKA_VERSION == 1 diff --git a/lib/lilka/src/lilka/controller.cpp b/lib/lilka/src/lilka/controller.cpp index 17e93260..241cd420 100644 --- a/lib/lilka/src/lilka/controller.cpp +++ b/lib/lilka/src/lilka/controller.cpp @@ -26,6 +26,10 @@ void IRAM_ATTR Controller::handle_interrupt(int stateIndex) { if (handlers[stateIndex] != NULL) { handlers[stateIndex](state->pressed); } + // Serial.print("Button "); + // Serial.print(stateIndex); + // Serial.print(" "); + // Serial.println(state->pressed ? "pressed" : "released"); state->time = micros(); } diff --git a/lib/lilka/src/lilka/display.cpp b/lib/lilka/src/lilka/display.cpp index acda643a..dd863d94 100644 --- a/lib/lilka/src/lilka/display.cpp +++ b/lib/lilka/src/lilka/display.cpp @@ -4,7 +4,7 @@ namespace lilka { -lilka::Display::Display() : Arduino_ST7789(new Arduino_ESP32SPI(LILKA_DISPLAY_DC, LILKA_DISPLAY_CS, LILKA_DISPLAY_SCK, LILKA_DISPLAY_MOSI, -1), LILKA_DISPLAY_RST, LILKA_DISPLAY_ROTATION, true, LILKA_DISPLAY_WIDTH, LILKA_DISPLAY_HEIGHT, 0, 20) {} +lilka::Display::Display() : Arduino_ST7789(new Arduino_ESP32SPI(LILKA_DISPLAY_DC, LILKA_DISPLAY_CS, LILKA_SPI_SCK, LILKA_SPI_MOSI, LILKA_SPI_MISO), LILKA_DISPLAY_RST, LILKA_DISPLAY_ROTATION, true, LILKA_DISPLAY_WIDTH, LILKA_DISPLAY_HEIGHT, 0, 20) {} void lilka::Display::begin() { Serial.print("Initializing display... "); diff --git a/lib/lilka/src/lilka/sdcard.cpp b/lib/lilka/src/lilka/sdcard.cpp index e116bd8c..03fd5a81 100644 --- a/lib/lilka/src/lilka/sdcard.cpp +++ b/lib/lilka/src/lilka/sdcard.cpp @@ -8,20 +8,38 @@ SDCard::SDCard() { void SDCard::begin() { Serial.print("Initializing SD card... "); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - SPIClass spi(HSPI); -#elif CONFIG_IDF_TARGET_ESP32C3 - SPIClass spi(FSPI); -#endif -#if SDCARD_CS < 0 +#if LILKA_SDCARD_CS < 0 Serial.println("failed: no CS pin"); #else - fs->begin(SDCARD_CS, spi); - Serial.println("done"); + fs->begin(LILKA_SDCARD_CS, SPI, 1000000); + Serial.print("done, SD card type: "); + switch (fs->cardType()) { + case CARD_NONE: + Serial.println("None"); + break; + case CARD_SD: + Serial.print("SD, "); + break; + case CARD_SDHC: + Serial.print("SDHC, "); + break; + default: + Serial.println("Unknown"); + break; + } + if (fs->cardType() == CARD_SD || fs->cardType() == CARD_SDHC) { + Serial.print("SD card size: "); + Serial.print(fs->totalBytes()); + Serial.println(" bytes"); + } #endif } +bool SDCard::available() { + return fs->cardType() == CARD_SD || fs->cardType() == CARD_SDHC; +} + int SDCard::listDir(String path, Entry entries[]) { File root = fs->open(path); if (!root) { @@ -49,6 +67,10 @@ int SDCard::listDir(String path, Entry entries[]) { i++; } root.close(); + // for (int i = 0; i < 1024; i++) { + // SPI.transfer(0xAA); // http://elm-chan.org/docs/mmc/mmc_e.html#spibus + // // SPI.write(0xAA); // http://elm-chan.org/docs/mmc/mmc_e.html#spibus + // } return i; } diff --git a/lib/lilka/src/lilka/sdcard.h b/lib/lilka/src/lilka/sdcard.h index d6915d8f..320ff9e7 100644 --- a/lib/lilka/src/lilka/sdcard.h +++ b/lib/lilka/src/lilka/sdcard.h @@ -21,6 +21,7 @@ class SDCard { public: SDCard(); void begin(); + bool available(); SDFS *fs; int listDir(String path, Entry entries[]); diff --git a/lib/lilka/src/lilka/ui/menu.cpp b/lib/lilka/src/lilka/ui.cpp similarity index 61% rename from lib/lilka/src/lilka/ui/menu.cpp rename to lib/lilka/src/lilka/ui.cpp index 28908fde..a1a5e6ea 100644 --- a/lib/lilka/src/lilka/ui/menu.cpp +++ b/lib/lilka/src/lilka/ui.cpp @@ -1,4 +1,4 @@ -#include "menu.h" +#include "ui.h" #include "lilka/display.h" #include "lilka/controller.h" @@ -7,6 +7,7 @@ namespace lilka { int ui_menu(String title, String menu[], int menu_size, int cursor) { // Arduino_TFT *gfx = lilka_display_get(); + Serial.println("Clear screen"); display.fillScreen(display.color565(0, 0, 0)); while (1) { display.setCursor(32, 48); @@ -57,4 +58,35 @@ int ui_menu(String title, String menu[], int menu_size, int cursor) { } } +void ui_alert(String title, String message) { + int top = LILKA_DISPLAY_HEIGHT / 8; + int mid = LILKA_DISPLAY_HEIGHT / 8 * 2; + int bottom = LILKA_DISPLAY_HEIGHT / 8 * 7; + + int left = LILKA_DISPLAY_WIDTH / 8; + int right = LILKA_DISPLAY_WIDTH / 8 * 7; + int width = right - left; + int xMargin = 4; + + display.fillRect(left, top, width, mid - top, display.color565(32, 96, 96)); + display.setFont(u8g2_font_6x13_t_cyrillic); + display.setTextSize(2); + display.setTextBound(left + xMargin, top, width - xMargin * 2, mid - top); + display.setCursor(left + xMargin, top + 13 * 2); + display.println(title); + + display.fillRect(left + xMargin, mid, width - xMargin * 2, bottom - mid, display.color565(32, 32, 32)); + display.setFont(u8g2_font_10x20_t_cyrillic); + display.setTextSize(1); + display.setTextBound(left + xMargin, top, width - xMargin * 2, bottom - mid); + display.setCursor(left, mid + 20); + display.println(message); + while (controller.state().start) { + delay(10); + } + while (!controller.state().start) { + delay(10); + } +} + } // namespace lilka diff --git a/lib/lilka/src/lilka/ui/menu.h b/lib/lilka/src/lilka/ui.h similarity index 56% rename from lib/lilka/src/lilka/ui/menu.h rename to lib/lilka/src/lilka/ui.h index 4ce7529f..fed6d327 100644 --- a/lib/lilka/src/lilka/ui/menu.h +++ b/lib/lilka/src/lilka/ui.h @@ -1,12 +1,13 @@ -#ifndef LILKA_MENU_H -#define LILKA_MENU_H +#ifndef LILKA_UI_H +#define LILKA_UI_H #include namespace lilka { int ui_menu(String title, String menu[], int menu_size, int cursor); +void ui_alert(String title, String message); } // namespace lilka -#endif // LILKA_MENU_H +#endif // LILKA_UI_H