Add tinyfsm, start converting core functions to an FSM-based event loop
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
idf_component_register(
|
||||
SRCS "main.cpp" "app_console.cpp"
|
||||
SRCS "main.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES "audio" "drivers" "dev_console" "drivers" "database" "ui")
|
||||
REQUIRES "audio" "ui" "system_fsm" "events")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
#include "app_console.hpp"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "audio_playback.hpp"
|
||||
#include "database.hpp"
|
||||
#include "esp_console.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
namespace console {
|
||||
|
||||
static AppConsole* sInstance = nullptr;
|
||||
|
||||
std::string toSdPath(const std::string& filepath) {
|
||||
return std::string(drivers::kStoragePath) + "/" + filepath;
|
||||
}
|
||||
|
||||
int CmdListDir(int argc, char** argv) {
|
||||
static const std::string usage = "usage: ls [directory]";
|
||||
if (argc > 2) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (argc == 2) {
|
||||
path = toSdPath(argv[1]);
|
||||
} else {
|
||||
path = toSdPath("");
|
||||
}
|
||||
|
||||
DIR* dir;
|
||||
struct dirent* ent;
|
||||
dir = opendir(path.c_str());
|
||||
while ((ent = readdir(dir))) {
|
||||
std::cout << ent->d_name << std::endl;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterListDir() {
|
||||
esp_console_cmd_t cmd{.command = "ls",
|
||||
.help = "Lists SD contents",
|
||||
.hint = NULL,
|
||||
.func = &CmdListDir,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
int CmdPlayFile(int argc, char** argv) {
|
||||
static const std::string usage = "usage: play [file]";
|
||||
if (argc != 2) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string path = "/";
|
||||
sInstance->playback_->Play(path + argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterPlayFile() {
|
||||
esp_console_cmd_t cmd{.command = "play",
|
||||
.help = "Begins playback of the file at the given path",
|
||||
.hint = "filepath",
|
||||
.func = &CmdPlayFile,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
int CmdToggle(int argc, char** argv) {
|
||||
static const std::string usage = "usage: toggle";
|
||||
if (argc != 1) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// sInstance->playback_->Toggle();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterToggle() {
|
||||
esp_console_cmd_t cmd{.command = "toggle",
|
||||
.help = "Toggles between play and pause",
|
||||
.hint = NULL,
|
||||
.func = &CmdToggle,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
int CmdVolume(int argc, char** argv) {
|
||||
static const std::string usage = "usage: volume [0-255]";
|
||||
if (argc != 2) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
long int raw_vol = strtol(argv[1], NULL, 10);
|
||||
if (raw_vol < 0 || raw_vol > 255) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// sInstance->playback_->SetVolume((uint8_t)raw_vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterVolume() {
|
||||
esp_console_cmd_t cmd{
|
||||
.command = "vol",
|
||||
.help = "Changes the volume (between 0 and 254. 255 is mute.)",
|
||||
.hint = NULL,
|
||||
.func = &CmdVolume,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
int CmdAudioStatus(int argc, char** argv) {
|
||||
static const std::string usage = "usage: audio";
|
||||
if (argc != 1) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sInstance->playback_->LogStatus();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterAudioStatus() {
|
||||
esp_console_cmd_t cmd{.command = "audio",
|
||||
.help = "logs the current status of the audio pipeline",
|
||||
.hint = NULL,
|
||||
.func = &CmdAudioStatus,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
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_->Update();
|
||||
|
||||
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 CmdDbSongs(int argc, char** argv) {
|
||||
static const std::string usage = "usage: db_songs";
|
||||
if (argc != 1) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<database::Result<database::Song>> res(
|
||||
sInstance->database_->GetSongs(5).get());
|
||||
while (true) {
|
||||
for (database::Song s : res->values()) {
|
||||
std::cout << s.tags().title.value_or("[BLANK]") << std::endl;
|
||||
}
|
||||
if (res->next_page()) {
|
||||
auto continuation = res->next_page().value();
|
||||
res.reset(sInstance->database_->GetPage(&continuation).get());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterDbSongs() {
|
||||
esp_console_cmd_t cmd{.command = "db_songs",
|
||||
.help = "lists titles of ALL songs in the database",
|
||||
.hint = NULL,
|
||||
.func = &CmdDbSongs,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
int CmdDbDump(int argc, char** argv) {
|
||||
static const std::string usage = "usage: db_dump";
|
||||
if (argc != 1) {
|
||||
std::cout << usage << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "=== BEGIN DUMP ===" << std::endl;
|
||||
|
||||
std::unique_ptr<database::Result<std::string>> res(
|
||||
sInstance->database_->GetDump(5).get());
|
||||
while (true) {
|
||||
for (std::string s : res->values()) {
|
||||
std::cout << s << std::endl;
|
||||
}
|
||||
if (res->next_page()) {
|
||||
auto continuation = res->next_page().value();
|
||||
res.reset(
|
||||
sInstance->database_->GetPage<std::string>(&continuation).get());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "=== END DUMP ===" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterDbDump() {
|
||||
esp_console_cmd_t cmd{.command = "db_dump",
|
||||
.help = "prints every key/value pair in the db",
|
||||
.hint = NULL,
|
||||
.func = &CmdDbDump,
|
||||
.argtable = NULL};
|
||||
esp_console_cmd_register(&cmd);
|
||||
}
|
||||
|
||||
AppConsole::AppConsole(audio::AudioPlayback* playback,
|
||||
database::Database* database)
|
||||
: playback_(playback), database_(database) {
|
||||
sInstance = this;
|
||||
}
|
||||
AppConsole::~AppConsole() {
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
auto AppConsole::RegisterExtraComponents() -> void {
|
||||
RegisterListDir();
|
||||
RegisterPlayFile();
|
||||
RegisterToggle();
|
||||
RegisterVolume();
|
||||
RegisterAudioStatus();
|
||||
RegisterDbInit();
|
||||
RegisterDbSongs();
|
||||
RegisterDbDump();
|
||||
}
|
||||
|
||||
} // namespace console
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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,
|
||||
database::Database* database);
|
||||
virtual ~AppConsole();
|
||||
|
||||
audio::AudioPlayback* playback_;
|
||||
database::Database* database_;
|
||||
|
||||
protected:
|
||||
virtual auto RegisterExtraComponents() -> void;
|
||||
};
|
||||
|
||||
} // namespace console
|
||||
+9
-105
@@ -1,114 +1,18 @@
|
||||
#include <dirent.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/sdspi_host.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver_cache.hpp"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "freertos/projdefs.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
#include "app_console.hpp"
|
||||
#include "audio_playback.hpp"
|
||||
#include "battery.hpp"
|
||||
#include "dac.hpp"
|
||||
#include "database.hpp"
|
||||
#include "display.hpp"
|
||||
#include "display_init.hpp"
|
||||
#include "gpio_expander.hpp"
|
||||
#include "i2c.hpp"
|
||||
#include "lvgl_task.hpp"
|
||||
#include "samd.hpp"
|
||||
#include "spi.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "touchwheel.hpp"
|
||||
#include "tinyfsm.hpp"
|
||||
|
||||
static const char* TAG = "MAIN";
|
||||
#include "audio_fsm.hpp"
|
||||
#include "event_queue.hpp"
|
||||
#include "system_fsm.hpp"
|
||||
#include "ui_fsm.hpp"
|
||||
|
||||
extern "C" void app_main(void) {
|
||||
ESP_LOGI(TAG, "Initialising peripherals");
|
||||
tinyfsm::FsmList<system_fsm::SystemState, ui::UiState,
|
||||
audio::AudioState>::start();
|
||||
|
||||
ESP_ERROR_CHECK(drivers::init_i2c());
|
||||
ESP_ERROR_CHECK(drivers::init_spi());
|
||||
std::unique_ptr<drivers::DriverCache> drivers =
|
||||
std::make_unique<drivers::DriverCache>();
|
||||
|
||||
ESP_LOGI(TAG, "Init GPIOs");
|
||||
drivers::GpioExpander* expander = drivers->AcquireGpios();
|
||||
|
||||
ESP_LOGI(TAG, "Init SAMD comms");
|
||||
drivers::Samd samd;
|
||||
ESP_LOGI(TAG, "It might have worked? Let's read something!");
|
||||
auto res = samd.ReadChargeStatus();
|
||||
if (res) {
|
||||
ESP_LOGI(TAG, "Charge status is %d", static_cast<uint8_t>(*res));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "no charge status?");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Enable power rails for development");
|
||||
expander->with(
|
||||
[&](auto& gpio) { gpio.set_pin(drivers::GpioExpander::AMP_EN, 1); });
|
||||
|
||||
ESP_LOGI(TAG, "Init battery measurement");
|
||||
drivers::Battery* battery = new drivers::Battery();
|
||||
ESP_LOGI(TAG, "it's reading %d mV!", (int)battery->Millivolts());
|
||||
|
||||
ESP_LOGI(TAG, "Init SD card");
|
||||
auto storage = drivers->AcquireStorage();
|
||||
if (!storage) {
|
||||
ESP_LOGE(TAG, "Failed! Do you have an SD card?");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Init touch wheel");
|
||||
std::shared_ptr<drivers::TouchWheel> touchwheel =
|
||||
drivers->AcquireTouchWheel();
|
||||
|
||||
std::atomic<bool> lvgl_quit;
|
||||
TaskHandle_t lvgl_task_handle;
|
||||
ui::StartLvgl(drivers.get(), &lvgl_quit, &lvgl_task_handle);
|
||||
|
||||
std::unique_ptr<audio::AudioPlayback> playback;
|
||||
if (storage) {
|
||||
ESP_LOGI(TAG, "Init audio pipeline");
|
||||
playback = std::make_unique<audio::AudioPlayback>(drivers.get());
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Init database");
|
||||
std::unique_ptr<database::Database> db;
|
||||
auto db_res = database::Database::Open();
|
||||
if (db_res.has_value()) {
|
||||
db.reset(db_res.value());
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Waiting for background tasks before launching console...");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
ESP_LOGI(TAG, "Launch console");
|
||||
console::AppConsole console(playback.get(), db.get());
|
||||
console.Launch();
|
||||
|
||||
uint8_t prev_position = 0;
|
||||
auto& queue = events::EventQueue::GetInstance();
|
||||
while (1) {
|
||||
touchwheel->Update();
|
||||
auto wheel_data = touchwheel->GetTouchWheelData();
|
||||
if (wheel_data.wheel_position != prev_position) {
|
||||
prev_position = wheel_data.wheel_position;
|
||||
ESP_LOGI(TAG, "Touch wheel pos: %u", prev_position);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
queue.Service(portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user