summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-06-07 10:30:33 +1000
committerjacqueline <me@jacqueline.id.au>2023-06-07 10:30:33 +1000
commit2a568846bd8f1c9e23e86e7570557eed6f18cf9f (patch)
tree3c152311311233eda762bb8b441ad44b50800cb8 /src
parent610991455d335663de1dd6c0c6a3e0247ffd46df (diff)
downloadtangara-fw-2a568846bd8f1c9e23e86e7570557eed6f18cf9f.tar.gz
Cute brightness fade to avoid ugly startup :)
Diffstat (limited to 'src')
-rw-r--r--src/drivers/display.cpp20
-rw-r--r--src/drivers/include/display.hpp6
-rw-r--r--src/system_fsm/booting.cpp37
-rw-r--r--src/ui/include/ui_fsm.hpp17
-rw-r--r--src/ui/ui_fsm.cpp46
5 files changed, 72 insertions, 54 deletions
diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp
index 7a49e02b..dd4cecb8 100644
--- a/src/drivers/display.cpp
+++ b/src/drivers/display.cpp
@@ -123,9 +123,11 @@ auto Display::Create(GpioExpander* expander,
.hpoint = 0};
ESP_ERROR_CHECK(ledc_channel_config(&led_channel));
- ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 4096));
+ ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
+ ledc_fade_func_install(0);
+
// Next, init the SPI device
spi_device_interface_config_t spi_cfg = {
.command_bits = 0, // No command phase
@@ -180,9 +182,21 @@ auto Display::Create(GpioExpander* expander,
Display::Display(GpioExpander* gpio, spi_device_handle_t handle)
: gpio_(gpio),
handle_(handle),
- worker_task_(tasks::Worker::Start<tasks::Type::kUiFlush>()) {}
+ worker_task_(tasks::Worker::Start<tasks::Type::kUiFlush>()),
+ display_on_(false),
+ brightness_(4096) {}
+
+Display::~Display() {
+ ledc_fade_func_uninstall();
+}
-Display::~Display() {}
+auto Display::SetDisplayOn(bool enabled) -> void {
+ display_on_ = enabled;
+
+ int new_duty = display_on_ ? brightness_ : 0;
+ ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, new_duty, 250);
+ ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT);
+}
void Display::SendInitialisationSequence(const uint8_t* data) {
// Hold onto the bus for the entire sequence so that we're not interrupted
diff --git a/src/drivers/include/display.hpp b/src/drivers/include/display.hpp
index d2e0c14b..b394dd9e 100644
--- a/src/drivers/include/display.hpp
+++ b/src/drivers/include/display.hpp
@@ -6,6 +6,7 @@
#pragma once
+#include <stdint.h>
#include <cstdint>
#include <memory>
@@ -35,6 +36,8 @@ class Display {
Display(GpioExpander* gpio, spi_device_handle_t handle);
~Display();
+ auto SetDisplayOn(bool) -> void;
+
/* Driver callback invoked by LVGL when there is new data to display. */
void OnLvglFlush(lv_disp_drv_t* disp_drv,
const lv_area_t* area,
@@ -46,6 +49,9 @@ class Display {
std::unique_ptr<tasks::Worker> worker_task_;
+ bool display_on_;
+ uint32_t brightness_;
+
lv_disp_draw_buf_t buffers_;
lv_disp_drv_t driver_;
lv_disp_t* display_ = nullptr;
diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp
index e18a8e8d..1ad8c02d 100644
--- a/src/system_fsm/booting.cpp
+++ b/src/system_fsm/booting.cpp
@@ -31,7 +31,7 @@ console::AppConsole* Booting::sAppConsole;
auto Booting::entry() -> void {
ESP_LOGI(kTag, "beginning tangara boot");
- ESP_LOGI(kTag, "installing bare minimum drivers");
+ ESP_LOGI(kTag, "installing early drivers");
// I2C and SPI are both always needed. We can't even power down or show an
// error without these.
@@ -44,39 +44,28 @@ auto Booting::entry() -> void {
assert(sGpioExpander != nullptr);
// Start bringing up LVGL now, since we have all of its prerequisites.
- ESP_LOGI(kTag, "installing ui drivers");
- lv_init();
- sDisplay.reset(drivers::Display::Create(sGpioExpander.get(),
- drivers::displays::kST7735R));
- assert(sDisplay != nullptr);
- sTouch.reset(drivers::TouchWheel::Create());
- if (sTouch != nullptr) {
- sRelativeTouch.reset(new drivers::RelativeWheel(sTouch.get()));
+ ESP_LOGI(kTag, "starting ui");
+ if (!ui::UiState::Init(sGpioExpander.get())) {
+ events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
+ FatalError());
+ return;
}
- // The UI FSM now has everything it needs to start setting up. Do this now,
- // so that we can properly show the user any errors that appear later.
- ui::UiState::Init(sGpioExpander.get(), sRelativeTouch, sDisplay);
- events::Dispatch<DisplayReady, ui::UiState>(DisplayReady());
-
- // These drivers are required for normal operation, but aren't critical for
- // booting. We will transition to the error state if these aren't present.
- ESP_LOGI(kTag, "installing required drivers");
+ // Install everything else that is certain to be needed.
+ ESP_LOGI(kTag, "installing remaining drivers");
sSamd.reset(drivers::Samd::Create());
+ sBattery.reset(drivers::Battery::Create());
- if (!sSamd || !sRelativeTouch) {
+ if (!sSamd || !sBattery) {
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
FatalError());
return;
}
- // These drivers are initialised on boot, but are recoverable (if weird) if
- // they fail.
- ESP_LOGI(kTag, "installing optional drivers");
- sBattery.reset(drivers::Battery::Create());
+ // At this point we've done all of the essential boot tasks. Start remaining
+ // state machines and inform them that the system is ready.
- // All drivers are now loaded, so we can finish initing the other state
- // machines.
+ ESP_LOGI(kTag, "starting audio");
if (!audio::AudioState::Init(sGpioExpander.get(), sDatabase)) {
events::Dispatch<FatalError, SystemState, ui::UiState, audio::AudioState>(
FatalError());
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index da6263b7..8b80f162 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -21,9 +21,7 @@ namespace ui {
class UiState : public tinyfsm::Fsm<UiState> {
public:
- static auto Init(drivers::GpioExpander* gpio_expander,
- const std::weak_ptr<drivers::RelativeWheel>& touchwheel,
- const std::weak_ptr<drivers::Display>& display) -> void;
+ static auto Init(drivers::GpioExpander* gpio_expander) -> bool;
virtual ~UiState() {}
@@ -42,23 +40,18 @@ class UiState : public tinyfsm::Fsm<UiState> {
protected:
static drivers::GpioExpander* sGpioExpander;
- static std::weak_ptr<drivers::RelativeWheel> sTouchWheel;
- static std::weak_ptr<drivers::Display> sDisplay;
+ static std::shared_ptr<drivers::TouchWheel> sTouchWheel;
+ static std::shared_ptr<drivers::RelativeWheel> sRelativeWheel;
+ static std::shared_ptr<drivers::Display> sDisplay;
static std::shared_ptr<Screen> sCurrentScreen;
};
namespace states {
-class PreBoot : public UiState {
- public:
- void react(const system_fsm::DisplayReady&) override;
- using UiState::react;
-};
-
class Splash : public UiState {
public:
- void entry() override;
+ void exit() override;
void react(const system_fsm::BootComplete&) override;
using UiState::react;
};
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index 5c59cf22..bdc1f89f 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -5,6 +5,8 @@
*/
#include "ui_fsm.hpp"
+#include <memory>
+#include "core/lv_obj.h"
#include "display.hpp"
#include "lvgl_task.hpp"
#include "relative_wheel.hpp"
@@ -17,33 +19,47 @@
namespace ui {
drivers::GpioExpander* UiState::sGpioExpander;
-std::weak_ptr<drivers::RelativeWheel> UiState::sTouchWheel;
-std::weak_ptr<drivers::Display> UiState::sDisplay;
+std::shared_ptr<drivers::TouchWheel> UiState::sTouchWheel;
+std::shared_ptr<drivers::RelativeWheel> UiState::sRelativeWheel;
+std::shared_ptr<drivers::Display> UiState::sDisplay;
std::shared_ptr<Screen> UiState::sCurrentScreen;
-auto UiState::Init(drivers::GpioExpander* gpio_expander,
- const std::weak_ptr<drivers::RelativeWheel>& touchwheel,
- const std::weak_ptr<drivers::Display>& display) -> void {
- assert(!touchwheel.expired());
- assert(!display.expired());
+auto UiState::Init(drivers::GpioExpander* gpio_expander) -> bool {
sGpioExpander = gpio_expander;
- sTouchWheel = touchwheel;
- sDisplay = display;
+
+ lv_init();
+ sDisplay.reset(
+ drivers::Display::Create(gpio_expander, drivers::displays::kST7735R));
+ if (sDisplay == nullptr) {
+ return false;
+ }
+
+ sTouchWheel.reset(drivers::TouchWheel::Create());
+ if (sTouchWheel != nullptr) {
+ sRelativeWheel.reset(new drivers::RelativeWheel(sTouchWheel.get()));
+ }
sCurrentScreen.reset(new screens::Splash());
- StartLvgl(sTouchWheel, sDisplay);
+ // Start the UI task even if init ultimately failed, so that we can show some
+ // kind of error screen to the user.
+ StartLvgl(sRelativeWheel, sDisplay);
+
+ if (sTouchWheel == nullptr) {
+ return false;
+ }
+ return true;
}
namespace states {
-void PreBoot::react(const system_fsm::DisplayReady& ev) {
- transit<Splash>();
+void Splash::exit() {
+ if (sDisplay != nullptr) {
+ sDisplay->SetDisplayOn(true);
+ }
}
-void Splash::entry() {}
-
void Splash::react(const system_fsm::BootComplete& ev) {
transit<Interactive>();
}
@@ -55,4 +71,4 @@ void Interactive::entry() {
} // namespace states
} // namespace ui
-FSM_INITIAL_STATE(ui::UiState, ui::states::PreBoot)
+FSM_INITIAL_STATE(ui::UiState, ui::states::Splash)