summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/database/CMakeLists.txt2
-rw-r--r--src/database/database.cpp59
-rw-r--r--src/database/env_esp.cpp2
-rw-r--r--src/database/include/database.hpp23
-rw-r--r--src/database/include/file_gatherer.hpp11
-rw-r--r--src/database/include/tag_processor.hpp13
-rw-r--r--src/database/tag_processor.cpp15
-rw-r--r--src/main/app_console.cpp54
-rw-r--r--src/main/app_console.hpp4
-rw-r--r--src/main/main.cpp16
10 files changed, 153 insertions, 46 deletions
diff --git a/src/database/CMakeLists.txt b/src/database/CMakeLists.txt
index 01365bf7..3f9ca6fb 100644
--- a/src/database/CMakeLists.txt
+++ b/src/database/CMakeLists.txt
@@ -1,5 +1,5 @@
idf_component_register(
- SRCS "env_esp.cpp" "database.cpp"
+ SRCS "env_esp.cpp" "database.cpp" "tag_processor.cpp"
INCLUDE_DIRS "include"
REQUIRES "result" "span" "esp_psram" "fatfs")
diff --git a/src/database/database.cpp b/src/database/database.cpp
index cfac77af..b677f4ba 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -4,6 +4,10 @@
#include "ff.h"
#include "leveldb/cache.h"
+#include "file_gatherer.hpp"
+#include "leveldb/iterator.h"
+#include "leveldb/slice.h"
+#include "tag_processor.hpp"
#include "env_esp.hpp"
#include "leveldb/options.h"
@@ -38,38 +42,37 @@ Database::Database(leveldb::DB* db, leveldb::Cache* cache)
Database::~Database() {}
-FRESULT scan_files(const std::string &path) {
- FRESULT res;
- FF_DIR dir;
- static FILINFO fno;
-
- res = f_opendir(&dir, path.c_str());
- if (res == FR_OK) {
- for (;;) {
- res = f_readdir(&dir, &fno);
- if (res != FR_OK || fno.fname[0] == 0) break;
- if (fno.fname[0] == '.') continue;
- if (fno.fattrib & AM_DIR) {
- std::string new_path = path + "/" + fno.fname;
- res = scan_files(new_path);
- if (res != FR_OK) break;
- } else {
- ESP_LOGI(kTag, "found %s", fno.fname);
- }
- }
- f_closedir(&dir);
- }
-
- return res;
+auto Database::Initialise() -> void {
+ leveldb::WriteOptions opt;
+ opt.sync = true;
+ FindFiles("", [&](const std::string &path) {
+ ESP_LOGI(kTag, "considering %s", path.c_str());
+ FileInfo info;
+ if (GetInfo(path, &info)) {
+ ESP_LOGI(kTag, "added as '%s'", info.title.c_str());
+ db_->Put(opt, "title:" + info.title, path);
+ }
+ });
+ db_->Put(opt, "title:coolkeywithoutval", leveldb::Slice());
}
-auto Database::Initialise() -> void {
- // TODO(jacqueline): Abstractions lol
- scan_files("/");
+auto Database::ByTitle() -> Iterator {
+ leveldb::Iterator *it = db_->NewIterator(leveldb::ReadOptions());
+ it->Seek("title:");
+ while (it->Valid()) {
+ ESP_LOGI(kTag, "%s : %s", it->key().ToString().c_str(), it->value().ToString().c_str());
+ it->Next();
+ }
+ return Iterator(it);
}
-auto Database::Update() -> void {
- // TODO(jacqueline): Incremental updates!
+auto Iterator::Next() -> std::optional<std::string> {
+ if (!it_->Valid()) {
+ return {};
+ }
+ std::string ret = it_->key().ToString();
+ it_->Next();
+ return ret;
}
} // namespace database
diff --git a/src/database/env_esp.cpp b/src/database/env_esp.cpp
index 45129a36..363421a7 100644
--- a/src/database/env_esp.cpp
+++ b/src/database/env_esp.cpp
@@ -465,7 +465,7 @@ void EspEnv::Schedule(
if (!started_background_thread_) {
started_background_thread_ = true;
xTaskCreate(reinterpret_cast<TaskFunction_t>(BackgroundThreadEntryPoint),
- "LVL_ONEOFF", 2048, reinterpret_cast<void*>(this), 3, NULL);
+ "LVL_ONEOFF", 16 * 1024, reinterpret_cast<void*>(this), 3, NULL);
}
BackgroundWorkItem item(background_work_function, background_work_arg);
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index b9df5fd4..cb1437df 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -1,13 +1,18 @@
#pragma once
+#include <string>
#include <memory>
+#include <optional>
#include "leveldb/cache.h"
#include "leveldb/db.h"
+#include "leveldb/iterator.h"
#include "result.hpp"
namespace database {
+class Iterator;
+
class Database {
public:
enum DatabaseError {
@@ -18,7 +23,10 @@ class Database {
~Database();
auto Initialise() -> void;
- auto Update() -> void;
+ auto ByTitle() -> Iterator;
+
+ Database(const Database&) = delete;
+ Database& operator=(const Database&) = delete;
private:
std::unique_ptr<leveldb::DB> db_;
@@ -27,4 +35,17 @@ class Database {
Database(leveldb::DB* db, leveldb::Cache* cache);
};
+class Iterator {
+ public:
+ explicit Iterator(leveldb::Iterator *it) : it_(it) {}
+
+ auto Next() -> std::optional<std::string>;
+
+ Iterator(const Iterator&) = delete;
+ Iterator& operator=(const Iterator&) = delete;
+
+ private:
+ std::unique_ptr<leveldb::Iterator> it_;
+};
+
} // namespace database
diff --git a/src/database/include/file_gatherer.hpp b/src/database/include/file_gatherer.hpp
index 47d40f88..7cf00b41 100644
--- a/src/database/include/file_gatherer.hpp
+++ b/src/database/include/file_gatherer.hpp
@@ -12,7 +12,7 @@ namespace database {
static_assert(sizeof(TCHAR) == sizeof(char), "TCHAR must be CHAR");
template <typename Callback>
-auto FindFiles(FATFS* fs, const std::string& root, Callback cb) -> void {
+auto FindFiles(const std::string& root, Callback cb) -> void {
std::deque<std::string> to_explore;
to_explore.push_back(root);
@@ -20,7 +20,7 @@ auto FindFiles(FATFS* fs, const std::string& root, Callback cb) -> void {
std::string next_path_str = to_explore.front();
const TCHAR* next_path = static_cast<const TCHAR*>(next_path_str.c_str());
- DIR dir;
+ FF_DIR dir;
FRESULT res = f_opendir(&dir, next_path);
if (res != FR_OK) {
// TODO: log.
@@ -30,10 +30,10 @@ auto FindFiles(FATFS* fs, const std::string& root, Callback cb) -> void {
for (;;) {
FILINFO info;
res = f_readdir(&dir, &info);
- if (info.fname == NULL) {
+ if (res != FR_OK || info.fname[0] == 0) {
// No more files in the directory.
break;
- } else if (info.fattrib & (AM_HID | AM_SYS)) {
+ } else if (info.fattrib & (AM_HID | AM_SYS) || info.fname[0] == '.') {
// System or hidden file. Ignore it and move on.
continue;
} else {
@@ -45,7 +45,8 @@ auto FindFiles(FATFS* fs, const std::string& root, Callback cb) -> void {
to_explore.push_back(full_path.str());
} else {
// This is a file! Let the callback know about it.
- std::invoke(cb, full_path.str(), info);
+ //std::invoke(cb, full_path.str(), info);
+ std::invoke(cb, full_path.str());
}
}
}
diff --git a/src/database/include/tag_processor.hpp b/src/database/include/tag_processor.hpp
index 0257fc92..88c95b61 100644
--- a/src/database/include/tag_processor.hpp
+++ b/src/database/include/tag_processor.hpp
@@ -1,3 +1,14 @@
#pragma once
-namespace database {} // namespace database
+#include <string>
+
+namespace database {
+
+struct FileInfo {
+ bool is_playable;
+ std::string title;
+};
+
+auto GetInfo(const std::string &path, FileInfo *out) -> bool;
+
+} // namespace database
diff --git a/src/database/tag_processor.cpp b/src/database/tag_processor.cpp
new file mode 100644
index 00000000..f2d520a4
--- /dev/null
+++ b/src/database/tag_processor.cpp
@@ -0,0 +1,15 @@
+#include "tag_processor.hpp"
+
+namespace database {
+
+auto GetInfo(const std::string &path, FileInfo *out) -> bool {
+ // TODO(jacqueline): bring in taglib for this
+ if (path.ends_with(".mp3")) {
+ out->is_playable = true;
+ out->title = path.substr(0, path.size() - 4);
+ return true;
+ }
+ return false;
+}
+
+} // namespace database
diff --git a/src/main/app_console.cpp b/src/main/app_console.cpp
index 40159f4e..859700f4 100644
--- a/src/main/app_console.cpp
+++ b/src/main/app_console.cpp
@@ -9,7 +9,9 @@
#include <string>
#include "audio_playback.hpp"
+#include "database.hpp"
#include "esp_console.h"
+#include "esp_log.h"
namespace console {
@@ -145,7 +147,55 @@ void RegisterAudioStatus() {
esp_console_cmd_register(&cmd);
}
-AppConsole::AppConsole(audio::AudioPlayback* playback) : playback_(playback) {
+int CmdDbInit(int argc, char** argv) {
+ static const std::string usage = "usage: db_init";
+ if (argc != 1) {
+ std::cout << usage << std::endl;
+ return 1;
+ }
+
+ sInstance->database_->Initialise();
+
+ return 0;
+}
+
+void RegisterDbInit() {
+ esp_console_cmd_t cmd{.command = "db_init",
+ .help = "scans for playable files and adds them to the database",
+ .hint = NULL,
+ .func = &CmdDbInit,
+ .argtable = NULL};
+ esp_console_cmd_register(&cmd);
+}
+
+int CmdDbTitles(int argc, char** argv) {
+ static const std::string usage = "usage: db_titles";
+ if (argc != 1) {
+ std::cout << usage << std::endl;
+ return 1;
+ }
+
+ database::Iterator it = sInstance->database_->ByTitle();
+ while (true) {
+ std::optional<std::string> title = it.Next();
+ if (!title) {
+ break;
+ }
+ std::cout << *title << std::endl;
+ }
+ return 0;
+}
+
+void RegisterDbTitles() {
+ esp_console_cmd_t cmd{.command = "db_titles",
+ .help = "lists titles of ALL songs in the database",
+ .hint = NULL,
+ .func = &CmdDbTitles,
+ .argtable = NULL};
+ esp_console_cmd_register(&cmd);
+}
+
+AppConsole::AppConsole(audio::AudioPlayback* playback, database::Database *database) : playback_(playback), database_(database) {
sInstance = this;
}
AppConsole::~AppConsole() {
@@ -158,6 +208,8 @@ auto AppConsole::RegisterExtraComponents() -> void {
RegisterToggle();
RegisterVolume();
RegisterAudioStatus();
+ RegisterDbInit();
+ RegisterDbTitles();
}
} // namespace console
diff --git a/src/main/app_console.hpp b/src/main/app_console.hpp
index f94bcb51..fcefd4d4 100644
--- a/src/main/app_console.hpp
+++ b/src/main/app_console.hpp
@@ -4,16 +4,18 @@
#include "audio_playback.hpp"
#include "console.hpp"
+#include "database.hpp"
#include "storage.hpp"
namespace console {
class AppConsole : public Console {
public:
- explicit AppConsole(audio::AudioPlayback* playback);
+ explicit AppConsole(audio::AudioPlayback* playback, database::Database *database);
virtual ~AppConsole();
audio::AudioPlayback* playback_;
+ database::Database *database_;
protected:
virtual auto RegisterExtraComponents() -> void;
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 312018cb..6ef7c61b 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -38,6 +38,7 @@
static const char* TAG = "MAIN";
void db_main(void* whatever) {
+ database::Database **arg_db = reinterpret_cast<database::Database**>(whatever);
ESP_LOGI(TAG, "Init database");
std::unique_ptr<database::Database> db;
auto db_res = database::Database::Open();
@@ -48,13 +49,13 @@ void db_main(void* whatever) {
ESP_LOGI(TAG, "database good :)");
}
- vTaskDelay(pdMS_TO_TICKS(2000));
+ *arg_db = db.get();
- db->Initialise();
+ db->ByTitle();
- vTaskDelay(pdMS_TO_TICKS(2000));
-
- db.reset();
+ while (1) {
+ vTaskDelay(portMAX_DELAY);
+ }
vTaskDelete(NULL);
}
@@ -89,7 +90,8 @@ extern "C" void app_main(void) {
StaticTask_t database_task_buffer = {};
StackType_t* database_stack = reinterpret_cast<StackType_t*>(
heap_caps_malloc(db_stack_size, MALLOC_CAP_SPIRAM));
- xTaskCreateStatic(&db_main, "LEVELDB", db_stack_size, NULL, 1, database_stack,
+ database::Database *db;
+ xTaskCreateStatic(&db_main, "LEVELDB", db_stack_size, &db, 1, database_stack,
&database_task_buffer);
ESP_LOGI(TAG, "Init touch wheel");
@@ -110,7 +112,7 @@ extern "C" void app_main(void) {
vTaskDelay(pdMS_TO_TICKS(1000));
ESP_LOGI(TAG, "Launch console");
- console::AppConsole console(playback.get());
+ console::AppConsole console(playback.get(), db);
console.Launch();
uint8_t prev_position = 0;