239 lines
7.3 KiB
C++
239 lines
7.3 KiB
C++
#include <Figments.h>
|
|
#include <U8g2lib.h>
|
|
#include "../../Static.h"
|
|
#include <ArduinoLog.h>
|
|
#include "../../LogService.h"
|
|
|
|
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, 16, 15, 4);
|
|
|
|
class U8Display : public Task {
|
|
public:
|
|
U8Display() : Task("U8Display") {}
|
|
|
|
enum ScreenState {
|
|
BootSplash,
|
|
Running,
|
|
Message,
|
|
Idle = Running
|
|
};
|
|
|
|
void onStart() {
|
|
Log.trace("display: starting redraw thread");
|
|
xTaskCreatePinnedToCore(
|
|
&U8Display::redrawTask,
|
|
name,
|
|
2000,
|
|
this,
|
|
1,
|
|
&m_renderTask, 0
|
|
);
|
|
}
|
|
|
|
void onStop() {
|
|
Log.trace("display: stopping redraw thread");
|
|
vTaskDelete(m_renderTask);
|
|
}
|
|
|
|
void handleEvent(const InputEvent& evt) {
|
|
m_lastEvent = evt;
|
|
if (m_state == Idle) {
|
|
switch(evt.intent) {
|
|
case InputEvent::NetworkStatus:
|
|
m_nextState = Message;
|
|
m_message = evt.asBool() ? "Online!" : "Offline :[";
|
|
break;
|
|
case InputEvent::SetPattern:
|
|
m_nextState = Message;
|
|
m_message = "Pattern: " + String(evt.asString());
|
|
break;
|
|
case InputEvent::SetPower:
|
|
m_nextState = Message;
|
|
m_message = evt.asBool() ? "Power On" : "Power Off";
|
|
break;
|
|
case InputEvent::SaveConfigurationRequest:
|
|
m_nextState = Message;
|
|
m_message = "Settings Saved!";
|
|
break;
|
|
case InputEvent::FirmwareUpdate:
|
|
m_nextState = Message;
|
|
m_message = "Firmware update";
|
|
break;
|
|
case InputEvent::PreviousPattern:
|
|
m_nextState = Message;
|
|
m_message = "Previous Pattern";
|
|
break;
|
|
case InputEvent::NextPattern:
|
|
m_nextState = Message;
|
|
m_message = "Next Pattern";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawSplash() {
|
|
//u8g2.setFont(u8g2_font_VCR_OSD_mr);
|
|
u8g2.setFont(u8g2_font_HelvetiPixelOutline_tr);
|
|
u8g2.setDrawColor(1);
|
|
uint8_t splashWidth = u8g2.getStrWidth("Renderbug!");
|
|
u8g2.drawStr(64 - splashWidth / 2, 32 - 15, "Renderbug!");
|
|
u8g2.setFont(u8g2_font_7x13B_mr);
|
|
u8g2.setCursor(15, 64 - 7);
|
|
u8g2.print("Version ");
|
|
u8g2.print(RENDERBUG_VERSION);
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
uint8_t sparkleX = (64 - splashWidth/2) + scale8(7-i, beatsin8(40)) * (splashWidth/7) + 5;
|
|
uint8_t sparkleY = scale8(3+i, beatsin8(40)) * 3 + 7;
|
|
u8g2.setDrawColor(2);
|
|
if (beatsin8(60*4) + i * 3 >= 170) {
|
|
u8g2.drawLine(sparkleX - 3, sparkleY - 3, sparkleX + 3, sparkleY + 3);
|
|
u8g2.drawLine(sparkleX + 3, sparkleY - 3, sparkleX - 3, sparkleY + 3);
|
|
} else if (beatsin8(60*4) + i * 2 >= 82) {
|
|
u8g2.drawLine(sparkleX - 4, sparkleY - 4, sparkleX + 2, sparkleY + 2);
|
|
u8g2.drawLine(sparkleX - 2, sparkleY - 2, sparkleX + 4, sparkleY + 4);
|
|
u8g2.drawLine(sparkleX + 4, sparkleY - 4, sparkleX - 2, sparkleY + 2);
|
|
u8g2.drawLine(sparkleX + 2, sparkleY - 2, sparkleX - 4, sparkleY + 4);
|
|
} else {
|
|
u8g2.drawLine(sparkleX - 2, sparkleY, sparkleX + 2, sparkleY);
|
|
u8g2.drawLine(sparkleX, sparkleY - 2, sparkleX, sparkleY + 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawMessage() {
|
|
//u8g2.setFont(u8g2_font_VCR_OSD_mr);
|
|
u8g2.setFont(u8g2_font_HelvetiPixelOutline_tr);
|
|
uint8_t splashWidth = u8g2.getStrWidth(m_message.c_str());
|
|
if (splashWidth >= 128) {
|
|
u8g2.setFont(u8g2_font_7x13B_mr);
|
|
splashWidth = u8g2.getStrWidth(m_message.c_str());
|
|
}
|
|
u8g2.drawStr(64 - splashWidth / 2, 32 - 15, m_message.c_str());
|
|
}
|
|
|
|
void drawTime() {
|
|
u8g2.setFont(u8g2_font_7x13O_tn);
|
|
u8g2.setCursor(0, 64);
|
|
struct tm timeinfo;
|
|
Platform::getLocalTime(&timeinfo);
|
|
uint8_t hour = timeinfo.tm_hour;
|
|
uint8_t minute = timeinfo.tm_min;
|
|
u8g2.print(hour);
|
|
u8g2.print(":");
|
|
u8g2.print(minute);
|
|
}
|
|
|
|
void drawState(ScreenState state) {
|
|
switch(state) {
|
|
case BootSplash:
|
|
drawSplash();
|
|
break;
|
|
case Message:
|
|
drawMessage();
|
|
break;
|
|
case Running:
|
|
uint8_t y = 11;
|
|
u8g2.setFont(u8g2_font_7x13B_mr);
|
|
u8g2.setCursor(0, y);
|
|
u8g2.print("FPS: ");
|
|
u8g2.setFont(u8g2_font_7x13O_tn);
|
|
u8g2.print(FastLED.getFPS());
|
|
y += 12;
|
|
u8g2.setCursor(0, y);
|
|
u8g2.setFont(u8g2_font_7x13B_mr);
|
|
u8g2.print("Last event: ");
|
|
y += 7;
|
|
u8g2.setCursor(10, y);
|
|
u8g2.setFont(u8g2_font_4x6_tr);
|
|
const char* intentName = LogService::intentName(m_lastEvent.intent);
|
|
if (intentName) {
|
|
u8g2.print(intentName);
|
|
} else {
|
|
u8g2.print("<");
|
|
u8g2.print(m_lastEvent.intent);
|
|
u8g2.print(">");
|
|
}
|
|
y += 12;
|
|
u8g2.setCursor(15, y);
|
|
u8g2.setFont(u8g2_font_7x13O_tf);
|
|
u8g2.print(LogService::eventValue(m_lastEvent));
|
|
drawTime();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void loop() {
|
|
EVERY_N_MILLISECONDS(8) {
|
|
xTaskNotifyGive(m_renderTask);
|
|
}
|
|
}
|
|
|
|
private:
|
|
ScreenState m_state = BootSplash;
|
|
ScreenState m_nextState = BootSplash;
|
|
uint8_t m_transitionFrame = 0;
|
|
uint8_t m_screenStartTime = 0;
|
|
InputEvent m_lastEvent;
|
|
String m_message;
|
|
|
|
TaskHandle_t m_renderTask;
|
|
void redraw() {
|
|
if (m_state != m_nextState) {
|
|
EVERY_N_MILLISECONDS(8) {
|
|
constexpr uint8_t speed = 11;
|
|
if (m_transitionFrame <= 255 - speed) {
|
|
m_transitionFrame += speed;
|
|
} else {
|
|
m_transitionFrame = 255;
|
|
}
|
|
uint8_t offset = ease8InOutApprox(m_transitionFrame);
|
|
u8g2.clearBuffer();
|
|
if (m_transitionFrame <= 128) {
|
|
uint8_t width = scale8(128, offset * 2);
|
|
u8g2.setDrawColor(1);
|
|
drawState(m_state);
|
|
u8g2.drawBox(0, 0, width, 64);
|
|
u8g2.setDrawColor(2);
|
|
u8g2.drawBox(width, 0, 8, 64);
|
|
} else {
|
|
uint8_t width = scale8(128, offset/2)*2;
|
|
u8g2.setDrawColor(1);
|
|
drawState(m_nextState);
|
|
u8g2.setDrawColor(2);
|
|
u8g2.drawBox(std::max(0, width - 8), 0, 8, 64);
|
|
u8g2.setDrawColor(1);
|
|
u8g2.drawBox(width, 0, 128, 64);
|
|
}
|
|
u8g2.sendBuffer();
|
|
|
|
if (m_transitionFrame == 255) {
|
|
m_state = m_nextState;
|
|
m_screenStartTime = millis();
|
|
m_transitionFrame = 0;
|
|
}
|
|
}
|
|
} else {
|
|
u8g2.clearBuffer();
|
|
drawState(m_state);
|
|
u8g2.sendBuffer();
|
|
uint16_t screenTime = millis() - m_screenStartTime;
|
|
if (screenTime >= 7000 && m_state != Idle) {
|
|
m_nextState = Idle;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void redrawTask(void* data) {
|
|
u8g2.begin();
|
|
U8Display* self = static_cast<U8Display*>(data);
|
|
self->m_screenStartTime = millis();
|
|
while (true) {
|
|
self->redraw();
|
|
ulTaskNotifyTake(0, portMAX_DELAY);
|
|
}
|
|
}
|
|
};
|
|
|
|
STATIC_ALLOC(U8Display);
|
|
STATIC_TASK(U8Display);
|