diff --git a/src/app_console/app_console.cpp b/src/app_console/app_console.cpp index 457d66f6..81a49e99 100644 --- a/src/app_console/app_console.cpp +++ b/src/app_console/app_console.cpp @@ -20,14 +20,11 @@ #include "esp_console.h" #include "esp_log.h" #include "event_queue.hpp" +#include "ff.h" namespace console { -static AppConsole* sInstance = nullptr; - -std::string toSdPath(const std::string& filepath) { - return std::string("/") + filepath; -} +std::weak_ptr AppConsole::sDatabase; int CmdListDir(int argc, char** argv) { static const std::string usage = "usage: ls [directory]"; @@ -36,7 +33,7 @@ int CmdListDir(int argc, char** argv) { return 1; } - auto lock = sInstance->database_.lock(); + auto lock = AppConsole::sDatabase.lock(); if (lock == nullptr) { std::cout << "storage is not available" << std::endl; return 1; @@ -44,18 +41,38 @@ int CmdListDir(int argc, char** argv) { std::string path; if (argc == 2) { - path = toSdPath(argv[1]); + path = argv[1]; } else { - path = toSdPath(""); + path = ""; + } + + FF_DIR dir; + FRESULT res = f_opendir(&dir, path.c_str()); + if (res != FR_OK) { + std::cout << "failed to open directory. does it exist?" << std::endl; + return 1; } - DIR* dir; - struct dirent* ent; - dir = opendir(path.c_str()); - while ((ent = readdir(dir))) { - std::cout << ent->d_name << std::endl; + for (;;) { + FILINFO info; + res = f_readdir(&dir, &info); + if (res != FR_OK || info.fname[0] == 0) { + // No more files in the directory. + break; + } else { + std::cout << path; + if (!path.ends_with('/') && !path.empty()) { + std::cout << '/'; + } + std::cout << info.fname; + if (info.fattrib & AM_DIR) { + std::cout << '/'; + } + std::cout << std::endl; + } } - closedir(dir); + + f_closedir(&dir); return 0; } @@ -101,7 +118,7 @@ int CmdDbInit(int argc, char** argv) { return 1; } - auto db = sInstance->database_.lock(); + auto db = AppConsole::sDatabase.lock(); if (!db) { std::cout << "no database open" << std::endl; return 1; @@ -128,13 +145,13 @@ int CmdDbTracks(int argc, char** argv) { return 1; } - auto db = sInstance->database_.lock(); + auto db = AppConsole::sDatabase.lock(); if (!db) { std::cout << "no database open" << std::endl; return 1; } std::unique_ptr> res( - db->GetTracks(5).get()); + db->GetTracks(20).get()); while (true) { for (database::Track s : res->values()) { std::cout << s.tags().title.value_or("[BLANK]") << std::endl; @@ -166,7 +183,7 @@ int CmdDbDump(int argc, char** argv) { return 1; } - auto db = sInstance->database_.lock(); + auto db = AppConsole::sDatabase.lock(); if (!db) { std::cout << "no database open" << std::endl; return 1; @@ -201,14 +218,6 @@ void RegisterDbDump() { esp_console_cmd_register(&cmd); } -AppConsole::AppConsole(const std::weak_ptr& database) - : database_(database) { - sInstance = this; -} -AppConsole::~AppConsole() { - sInstance = nullptr; -} - auto AppConsole::RegisterExtraComponents() -> void { RegisterListDir(); RegisterPlayFile(); diff --git a/src/app_console/include/app_console.hpp b/src/app_console/include/app_console.hpp index 32242d16..48ce0d38 100644 --- a/src/app_console/include/app_console.hpp +++ b/src/app_console/include/app_console.hpp @@ -15,10 +15,7 @@ namespace console { class AppConsole : public Console { public: - explicit AppConsole(const std::weak_ptr& database); - virtual ~AppConsole(); - - const std::weak_ptr& database_; + static std::weak_ptr sDatabase; protected: virtual auto RegisterExtraComponents() -> void; diff --git a/src/database/database.cpp b/src/database/database.cpp index 9206256f..a96b3eab 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -17,6 +17,7 @@ #include "esp_log.h" #include "ff.h" +#include "freertos/projdefs.h" #include "leveldb/cache.h" #include "leveldb/db.h" #include "leveldb/iterator.h" @@ -68,12 +69,13 @@ auto Database::Open(IFileGatherer* gatherer, ITagParser* parser) return cpp::fail(DatabaseError::ALREADY_OPEN); } + leveldb::sBackgroundThread.reset( + tasks::Worker::Start()); std::shared_ptr worker( tasks::Worker::Start()); - leveldb::sBackgroundThread = std::weak_ptr(worker); return worker ->Dispatch>( - [&]() -> cpp::result { + [=]() -> cpp::result { leveldb::DB* db; leveldb::Cache* cache = leveldb::NewLRUCache(24 * 1024); leveldb::Options options; @@ -121,7 +123,7 @@ Database::~Database() { delete db_; delete cache_; - leveldb::sBackgroundThread = std::weak_ptr(); + leveldb::sBackgroundThread.reset(); sIsDbOpen.store(false); } diff --git a/src/database/env_esp.cpp b/src/database/env_esp.cpp index 704e0a54..ad1f2221 100644 --- a/src/database/env_esp.cpp +++ b/src/database/env_esp.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,7 @@ namespace leveldb { -std::weak_ptr sBackgroundThread; +std::shared_ptr sBackgroundThread; std::string ErrToStr(FRESULT err) { switch (err) { @@ -463,7 +464,7 @@ EspEnv::EspEnv() {} void EspEnv::Schedule( void (*background_work_function)(void* background_work_arg), void* background_work_arg) { - auto worker = sBackgroundThread.lock(); + auto worker = sBackgroundThread; if (worker) { worker->Dispatch( [=]() { std::invoke(background_work_function, background_work_arg); }); diff --git a/src/database/include/env_esp.hpp b/src/database/include/env_esp.hpp index c7da6d91..eba6e8a9 100644 --- a/src/database/include/env_esp.hpp +++ b/src/database/include/env_esp.hpp @@ -18,7 +18,7 @@ namespace leveldb { -extern std::weak_ptr sBackgroundThread; +extern std::shared_ptr sBackgroundThread; // Tracks the files locked by EspEnv::LockFile(). // diff --git a/src/database/tag_parser.cpp b/src/database/tag_parser.cpp index 5bca0b58..83b0a796 100644 --- a/src/database/tag_parser.cpp +++ b/src/database/tag_parser.cpp @@ -73,6 +73,12 @@ static const char* kTag = "TAGS"; auto TagParserImpl::ReadAndParseTags(const std::string& path, TrackTags* out) -> bool { + if (path.ends_with(".m4a")) { + // TODO(jacqueline): Re-enabled once libtags is fixed. + ESP_LOGW(kTag, "skipping m4a %s", path.c_str()); + return false; + } + libtags::Aux aux; aux.tags = out; if (f_stat(path.c_str(), &aux.info) != FR_OK || diff --git a/src/drivers/samd.cpp b/src/drivers/samd.cpp index 5ed99666..e87fc9d8 100644 --- a/src/drivers/samd.cpp +++ b/src/drivers/samd.cpp @@ -38,7 +38,7 @@ Samd::Samd() { .read(&raw_res, I2C_MASTER_NACK) .stop(); ESP_LOGI(kTag, "checking samd firmware rev"); - ESP_ERROR_CHECK(transaction.Execute()); + transaction.Execute(); ESP_LOGI(kTag, "samd firmware: %u", raw_res); } Samd::~Samd() {} @@ -53,7 +53,7 @@ auto Samd::ReadChargeStatus() -> std::optional { .read(&raw_res, I2C_MASTER_NACK) .stop(); ESP_LOGI(kTag, "checking charge status"); - ESP_ERROR_CHECK(transaction.Execute()); + transaction.Execute(); ESP_LOGI(kTag, "raw charge status: %x", raw_res); uint8_t usb_state = raw_res & 0b11; @@ -83,7 +83,7 @@ auto Samd::WriteAllowUsbMsc(bool is_allowed) -> void { .write_addr(kAddress, I2C_MASTER_WRITE) .write_ack(kRegisterUsbMsc, is_allowed) .stop(); - ESP_ERROR_CHECK(transaction.Execute()); + transaction.Execute(); } auto Samd::ReadUsbMscStatus() -> UsbMscStatus { diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp index cd189388..576b6dad 100644 --- a/src/drivers/touchwheel.cpp +++ b/src/drivers/touchwheel.cpp @@ -65,7 +65,7 @@ void TouchWheel::WriteRegister(uint8_t reg, uint8_t val) { .write_addr(kTouchWheelAddress, I2C_MASTER_WRITE) .write_ack(reg, val) .stop(); - ESP_ERROR_CHECK(transaction.Execute()); + transaction.Execute(); } uint8_t TouchWheel::ReadRegister(uint8_t reg) { @@ -78,7 +78,7 @@ uint8_t TouchWheel::ReadRegister(uint8_t reg) { .write_addr(kTouchWheelAddress, I2C_MASTER_READ) .read(&res, I2C_MASTER_NACK) .stop(); - ESP_ERROR_CHECK(transaction.Execute()); + transaction.Execute(); return res; } diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index 1ad8c02d..1e1b2959 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -27,8 +27,6 @@ namespace states { static const char kTag[] = "BOOT"; -console::AppConsole* Booting::sAppConsole; - auto Booting::entry() -> void { ESP_LOGI(kTag, "beginning tangara boot"); ESP_LOGI(kTag, "installing early drivers"); @@ -78,7 +76,7 @@ auto Booting::entry() -> void { auto Booting::exit() -> void { // TODO(jacqueline): Gate this on something. Debug flag? Flashing mode? - sAppConsole = new console::AppConsole(sDatabase); + sAppConsole = new console::AppConsole(); sAppConsole->Launch(); } diff --git a/src/system_fsm/include/system_fsm.hpp b/src/system_fsm/include/system_fsm.hpp index 89cdcf47..037c0a0e 100644 --- a/src/system_fsm/include/system_fsm.hpp +++ b/src/system_fsm/include/system_fsm.hpp @@ -56,6 +56,8 @@ class SystemState : public tinyfsm::Fsm { static std::shared_ptr sStorage; static std::shared_ptr sDisplay; static std::shared_ptr sDatabase; + + static console::AppConsole* sAppConsole; }; namespace states { @@ -65,9 +67,6 @@ namespace states { * looks good. */ class Booting : public SystemState { - private: - static console::AppConsole* sAppConsole; - public: void entry() override; void exit() override; diff --git a/src/system_fsm/running.cpp b/src/system_fsm/running.cpp index 9116ec9d..f9ff6140 100644 --- a/src/system_fsm/running.cpp +++ b/src/system_fsm/running.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-only */ +#include "app_console.hpp" #include "freertos/projdefs.h" #include "result.hpp" @@ -28,6 +29,7 @@ void Running::entry() { vTaskDelay(pdMS_TO_TICKS(250)); auto storage_res = drivers::SdStorage::Create(sGpioExpander.get()); if (storage_res.has_error()) { + ESP_LOGW(kTag, "failed to mount!"); events::Dispatch( StorageError()); return; @@ -38,11 +40,13 @@ void Running::entry() { ESP_LOGI(kTag, "opening database"); auto database_res = database::Database::Open(); if (database_res.has_error()) { + ESP_LOGW(kTag, "failed to open!"); events::Dispatch( StorageError()); return; } sDatabase.reset(database_res.value()); + console::AppConsole::sDatabase = sDatabase; ESP_LOGI(kTag, "storage loaded okay"); events::Dispatch( diff --git a/src/system_fsm/system_fsm.cpp b/src/system_fsm/system_fsm.cpp index bcab298c..c59c0908 100644 --- a/src/system_fsm/system_fsm.cpp +++ b/src/system_fsm/system_fsm.cpp @@ -20,6 +20,8 @@ std::shared_ptr SystemState::sStorage; std::shared_ptr SystemState::sDisplay; std::shared_ptr SystemState::sDatabase; +console::AppConsole* SystemState::sAppConsole; + void SystemState::react(const FatalError& err) { if (!is_in_state()) { transit(); diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp index 2477d8b9..c28f463c 100644 --- a/src/tasks/tasks.cpp +++ b/src/tasks/tasks.cpp @@ -5,7 +5,9 @@ */ #include "tasks.hpp" + #include + #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" @@ -31,6 +33,10 @@ template <> auto Name() -> std::string { return "DB"; } +template <> +auto Name() -> std::string { + return "DB_BG"; +} template auto AllocateStack() -> cpp::span; @@ -39,7 +45,7 @@ auto AllocateStack() -> cpp::span; // amount of stack space. template <> auto AllocateStack() -> cpp::span { - std::size_t size = 48 * 1024; + std::size_t size = 32 * 1024; return {static_cast(heap_caps_malloc(size, MALLOC_CAP_DEFAULT)), size}; } @@ -67,6 +73,12 @@ auto AllocateStack() -> cpp::span { return {static_cast(heap_caps_malloc(size, MALLOC_CAP_SPIRAM)), size}; } +template <> +auto AllocateStack() -> cpp::span { + std::size_t size = 256 * 1024; + return {static_cast(heap_caps_malloc(size, MALLOC_CAP_SPIRAM)), + size}; +} // 2048 bytes in internal ram // 302 KiB in external ram. @@ -106,6 +118,10 @@ template <> auto Priority() -> UBaseType_t { return 8; } +template <> +auto Priority() -> UBaseType_t { + return 7; +} template auto WorkerQueueSize() -> std::size_t; @@ -114,6 +130,10 @@ template <> auto WorkerQueueSize() -> std::size_t { return 8; } +template <> +auto WorkerQueueSize() -> std::size_t { + return 8; +} template <> auto WorkerQueueSize() -> std::size_t { diff --git a/src/tasks/tasks.hpp b/src/tasks/tasks.hpp index 955acd9f..4e5dfd17 100644 --- a/src/tasks/tasks.hpp +++ b/src/tasks/tasks.hpp @@ -36,6 +36,8 @@ enum class Type { kAudio, // Task for running database queries. kDatabase, + // Task for internal database operations + kDatabaseBackground, }; template @@ -102,6 +104,9 @@ class Worker { } ~Worker(); + + Worker(const Worker&) = delete; + Worker& operator=(const Worker&) = delete; }; /* Specialisation of Evaluate for functions that return nothing. */