Files
Flipdot-display/src/esp32/logic/display_controller.cpp
T

187 lines
4.0 KiB
C++
Raw Normal View History

#include "logic/display_controller.h"
#include "config.h"
#include "logic/schedule.h"
DisplayController::DisplayController(DisplayPower &power, Frames &frames) : _power(power), _frames(frames)
{
}
2026-10-13 01:52:34 +02:00
void DisplayController::setSettings(const ScheduleSettings &schedule, const ClockSettings &clock)
{
_schedule = schedule;
_clock = clock;
_content_revision++; // e.g. the No WiFi setting changed: redraw
2026-10-13 01:52:34 +02:00
}
void DisplayController::setEffectTime(uint32_t ms)
{
_effect_time = ms;
}
2026-10-13 01:52:34 +02:00
void DisplayController::setPage(Page page)
{
_page = page;
_content_revision++;
}
void DisplayController::pageChanged()
{
_content_revision++;
}
void DisplayController::showLive(uint32_t now)
{
_live = true;
_live_since = now;
_content_revision++;
}
void DisplayController::stopLive()
{
_live = false;
_content_revision++;
}
bool DisplayController::liveActive() const
{
return _live;
}
void DisplayController::setPowerEnabled(bool enabled)
{
_power_enabled = enabled;
}
bool DisplayController::powerEnabled() const
{
return _power_enabled;
}
void DisplayController::update(uint32_t now, bool time_valid, const LocalTime &time, bool wifi_connected)
{
2026-10-13 01:34:04 +02:00
if (wifi_connected)
_wifi_lost = false;
else if (!_wifi_lost)
{
_wifi_lost = true;
_wifi_lost_since = now;
}
2026-10-13 01:52:34 +02:00
bool show_no_wifi = _clock.no_wifi_screen && _wifi_lost && now - _wifi_lost_since >= NO_WIFI_SHOW_TIME;
if (_live && now - _live_since >= LIVE_TIMEOUT)
stopLive();
2026-10-13 01:34:04 +02:00
// Switched off elsewhere (power timer, Nano flashing): the Nano lost its frame
if (!_power.isOn())
_screen = Screen::Unknown;
if (_off_timer.expired(now))
{
_power.off();
_screen = Screen::Unknown;
return;
}
if (!_power_enabled)
{
if (_power.isOn())
{
_showOnce(Screen::Off);
_off_timer.request(now, CLEAR_BEFORE_OFF_TIME + _effect_time);
}
return;
}
2026-10-13 01:52:34 +02:00
// Live mode from the web UI: shown right away, whatever the time
if (_live)
{
_off_timer.cancel();
_ensureOn();
_showOnce(Screen::Live);
return;
}
// Keep the boot screen until the time is known
if (!time_valid)
return;
switch (scheduleFor(time.hour, time.minute, _schedule))
{
case ScheduleMode::Night:
if (_power.isOn())
{
_showOnce(Screen::Off);
_off_timer.request(now, POWER_OFF_DELAY);
}
break;
case ScheduleMode::Clock:
_off_timer.cancel();
2026-10-13 01:52:34 +02:00
_ensureOn();
if (_page == Page::Dynamic)
_showDynamic(now, time, show_no_wifi);
2026-10-13 01:52:34 +02:00
else
_showOnce(Screen::Page);
break;
case ScheduleMode::Standby:
2026-10-13 01:52:34 +02:00
// Flipdots keep their image without power, so the last image stays visible
if (_power.isOn())
_off_timer.request(now, POWER_OFF_DELAY);
break;
}
}
2026-10-13 01:52:34 +02:00
void DisplayController::_ensureOn()
{
if (_power.isOn())
return;
_power.on();
_screen = Screen::Unknown;
}
// Drawn again each minute (time, date and background can change), when the content changed,
// and as often as a moving page asks for (scrolling, seconds)
void DisplayController::_showDynamic(uint32_t now, const LocalTime &time, bool no_wifi)
{
Screen screen = no_wifi ? Screen::NoWifi : Screen::Dynamic;
bool redraw = _screen != screen || _shown_revision != _content_revision;
bool due = screen == Screen::Dynamic && _dynamic_moving && (int32_t)(now - _dynamic_due) >= 0;
if (!redraw && !due && _shown_hour == time.hour && _shown_minute == time.minute)
return;
2026-10-13 01:34:04 +02:00
if (no_wifi)
{
_frames.noWifi(time.hour, time.minute);
_dynamic_moving = false;
}
2026-10-13 01:34:04 +02:00
else
{
uint32_t wait = _frames.dynamicPage(time, now, redraw);
_dynamic_moving = wait != 0;
_dynamic_due = now + wait;
}
2026-10-13 01:34:04 +02:00
_screen = screen;
_shown_hour = time.hour;
_shown_minute = time.minute;
2026-10-13 01:52:34 +02:00
_shown_revision = _content_revision;
}
2026-10-13 01:52:34 +02:00
// Screens without the time: only sent again when they or their content changed
void DisplayController::_showOnce(Screen screen)
{
2026-10-13 01:52:34 +02:00
if (_screen == screen && _shown_revision == _content_revision)
return;
2026-10-13 01:52:34 +02:00
switch (screen)
{
case Screen::Page:
_frames.page();
break;
case Screen::Live:
_frames.live();
break;
default:
_frames.off();
2026-10-13 01:52:34 +02:00
break;
}
_screen = screen;
_shown_revision = _content_revision;
}