More refactorings again
This commit is contained in:
@ -311,6 +311,8 @@ set(sources
|
||||
displays/menus/mosfetsmenu.cpp
|
||||
displays/menus/motorfeedbackdebugmenu.cpp
|
||||
displays/menus/motorstatedebugmenu.cpp
|
||||
displays/menus/otamenu.cpp
|
||||
displays/menus/selectotabuildmenu.cpp
|
||||
displays/menus/presetsmenu.cpp
|
||||
displays/menus/profilesmenu.cpp
|
||||
displays/menus/selectbatterytypemenu.cpp
|
||||
|
@ -0,0 +1,126 @@
|
||||
#include "gameoflifedisplay.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
#include <tftinstance.h>
|
||||
#include <screenmanager.h>
|
||||
|
||||
void GameOfLifeDisplay::start()
|
||||
{
|
||||
m_grid = std::make_unique<std::bitset<GRIDX*GRIDY>>();
|
||||
m_newgrid = std::make_unique<std::bitset<GRIDX*GRIDY>>();
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::initScreen()
|
||||
{
|
||||
espgui::tft.setRotation(3);
|
||||
espgui::tft.fillScreen(TFT_BLACK);
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::redraw()
|
||||
{
|
||||
if (gen == 0)
|
||||
{
|
||||
espgui::tft.fillScreen(TFT_BLACK);
|
||||
initGrid();
|
||||
}
|
||||
|
||||
computeCA();
|
||||
drawGrid();
|
||||
|
||||
*m_grid = *m_newgrid;
|
||||
|
||||
if (++gen == 500)
|
||||
gen = 0;
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::stop()
|
||||
{
|
||||
espgui::tft.setRotation(0);
|
||||
m_grid = nullptr;
|
||||
m_newgrid = nullptr;
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::confirm()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::back()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::drawGrid()
|
||||
{
|
||||
uint16_t color = TFT_WHITE;
|
||||
for (int16_t x = 1; x < GRIDX - 1; x++) {
|
||||
for (int16_t y = 1; y < GRIDY - 1; y++) {
|
||||
if (((*m_grid)[index(x,y)]) != ((*m_newgrid)[index(x,y)])) {
|
||||
if ((*m_newgrid)[index(x,y)] == 1)
|
||||
color = 0xFFFF; //random(0xFFFF);
|
||||
else
|
||||
color = 0;
|
||||
espgui::tft.fillRect(CELLXY * x, CELLXY * y, CELLXY, CELLXY, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::initGrid()
|
||||
{
|
||||
for (int16_t x = 0; x < GRIDX; x++) {
|
||||
for (int16_t y = 0; y < GRIDY; y++) {
|
||||
(*m_newgrid)[index(x,y)] = 0;
|
||||
|
||||
if (x == 0 || x == GRIDX - 1 || y == 0 || y == GRIDY - 1)
|
||||
(*m_grid)[index(x,y)] = 0;
|
||||
else
|
||||
{
|
||||
if (cpputils::randomNumber<uint8_t>(4, espcpputils::esp_random_device{}) == 1)
|
||||
(*m_grid)[index(x,y)] = 1;
|
||||
else
|
||||
(*m_grid)[index(x,y)] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GameOfLifeDisplay::getNumberOfNeighbors(int x, int y)
|
||||
{
|
||||
int n{};
|
||||
for (auto xOffset : {-1,0,1})
|
||||
for (auto yOffset : {-1,0,1})
|
||||
{
|
||||
if (xOffset == 0 && yOffset == 0)
|
||||
continue;
|
||||
|
||||
const auto new_x = x+xOffset;
|
||||
const auto new_y = y+yOffset;
|
||||
|
||||
if (new_x >= 0 && new_y >= 0 &&
|
||||
new_x < GRIDX && new_y < GRIDY)
|
||||
n += (*m_grid)[index(new_x, new_y)];
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::computeCA()
|
||||
{
|
||||
for (int16_t x = 1; x < GRIDX; x++) {
|
||||
for (int16_t y = 1; y < GRIDY; y++) {
|
||||
int neighbors = getNumberOfNeighbors(x, y);
|
||||
if ((*m_grid)[index(x,y)] == true && (neighbors == 2 || neighbors == 3 ))
|
||||
(*m_newgrid)[index(x,y)] = true;
|
||||
else if ((*m_grid)[index(x,y)] == 1)
|
||||
(*m_newgrid)[index(x,y)] = false;
|
||||
if ((*m_grid)[index(x,y)] == false && (neighbors == 3))
|
||||
(*m_newgrid)[index(x,y)] = true;
|
||||
else if ((*m_grid)[index(x,y)] == 0)
|
||||
(*m_newgrid)[index(x,y)] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,22 @@
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
|
||||
// local includes
|
||||
#include "display.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
|
||||
namespace {
|
||||
class GameOfLifeDisplay : public Display, public ConfirmActionInterface<SwitchScreenAction<DemosMenu>>, public BackActionInterface<SwitchScreenAction<DemosMenu>>
|
||||
class GameOfLifeDisplay : public espgui::Display
|
||||
{
|
||||
using Base = espgui::Display;
|
||||
|
||||
public:
|
||||
void start() override;
|
||||
void initScreen() override;
|
||||
void redraw() override;
|
||||
void stop() override;
|
||||
|
||||
void confirm() override;
|
||||
void back() override;
|
||||
|
||||
private:
|
||||
|
||||
//Draws the grid on the display
|
||||
@ -71,114 +70,3 @@ private:
|
||||
|
||||
int gen = 0;
|
||||
};
|
||||
|
||||
void GameOfLifeDisplay::start()
|
||||
{
|
||||
m_grid = std::make_unique<std::bitset<GRIDX*GRIDY>>();
|
||||
m_newgrid = std::make_unique<std::bitset<GRIDX*GRIDY>>();
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::initScreen()
|
||||
{
|
||||
tft.setRotation(3);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::redraw()
|
||||
{
|
||||
if (gen == 0)
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
initGrid();
|
||||
}
|
||||
|
||||
computeCA();
|
||||
drawGrid();
|
||||
|
||||
*m_grid = *m_newgrid;
|
||||
|
||||
if (++gen == 500)
|
||||
gen = 0;
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::stop()
|
||||
{
|
||||
tft.setRotation(0);
|
||||
m_grid = nullptr;
|
||||
m_newgrid = nullptr;
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::drawGrid()
|
||||
{
|
||||
uint16_t color = TFT_WHITE;
|
||||
for (int16_t x = 1; x < GRIDX - 1; x++) {
|
||||
for (int16_t y = 1; y < GRIDY - 1; y++) {
|
||||
if (((*m_grid)[index(x,y)]) != ((*m_newgrid)[index(x,y)])) {
|
||||
if ((*m_newgrid)[index(x,y)] == 1)
|
||||
color = 0xFFFF; //random(0xFFFF);
|
||||
else
|
||||
color = 0;
|
||||
tft.fillRect(CELLXY * x, CELLXY * y, CELLXY, CELLXY, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::initGrid()
|
||||
{
|
||||
for (int16_t x = 0; x < GRIDX; x++) {
|
||||
for (int16_t y = 0; y < GRIDY; y++) {
|
||||
(*m_newgrid)[index(x,y)] = 0;
|
||||
|
||||
if (x == 0 || x == GRIDX - 1 || y == 0 || y == GRIDY - 1)
|
||||
(*m_grid)[index(x,y)] = 0;
|
||||
else
|
||||
{
|
||||
if (cpputils::randomNumber<uint8_t>(4, espcpputils::esp_random_device{}) == 1)
|
||||
(*m_grid)[index(x,y)] = 1;
|
||||
else
|
||||
(*m_grid)[index(x,y)] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GameOfLifeDisplay::getNumberOfNeighbors(int x, int y)
|
||||
{
|
||||
int n{};
|
||||
for (auto xOffset : {-1,0,1})
|
||||
for (auto yOffset : {-1,0,1})
|
||||
{
|
||||
if (xOffset == 0 && yOffset == 0)
|
||||
continue;
|
||||
|
||||
const auto new_x = x+xOffset;
|
||||
const auto new_y = y+yOffset;
|
||||
|
||||
if (new_x >= 0 && new_y >= 0 &&
|
||||
new_x < GRIDX && new_y < GRIDY)
|
||||
n += (*m_grid)[index(new_x, new_y)];
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void GameOfLifeDisplay::computeCA()
|
||||
{
|
||||
for (int16_t x = 1; x < GRIDX; x++) {
|
||||
for (int16_t y = 1; y < GRIDY; y++) {
|
||||
int neighbors = getNumberOfNeighbors(x, y);
|
||||
if ((*m_grid)[index(x,y)] == true && (neighbors == 2 || neighbors == 3 ))
|
||||
(*m_newgrid)[index(x,y)] = true;
|
||||
else if ((*m_grid)[index(x,y)] == 1)
|
||||
(*m_newgrid)[index(x,y)] = false;
|
||||
if ((*m_grid)[index(x,y)] == false && (neighbors == 3))
|
||||
(*m_newgrid)[index(x,y)] = true;
|
||||
else if ((*m_grid)[index(x,y)] == 0)
|
||||
(*m_newgrid)[index(x,y)] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
46
main/displays/menus/otamenu.cpp
Normal file
46
main/displays/menus/otamenu.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "otamenu.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include "actioninterface.h"
|
||||
#include "actions/dummyaction.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
#include "icons/back.h"
|
||||
|
||||
// local includes
|
||||
#include "utils.h"
|
||||
#include "icons/update.h"
|
||||
#include "icons/presets.h"
|
||||
#include "buildserver.h"
|
||||
#include "displays/menus/selectotabuildmenu.h"
|
||||
#include "displays/updatedisplay.h"
|
||||
#include "displays/menus/selectbuildservermenu.h"
|
||||
#include "displays/menus/mainmenu.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class RedownloadJsonAction : public virtual espgui::ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override
|
||||
{
|
||||
redownload = true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
OtaMenu::OtaMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILD>, SwitchScreenAction<SelectBuildMenu>, StaticMenuItemIcon<&bobbyicons::presets>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_UPDATENOW>, SwitchScreenAction<UpdateDisplay>, StaticMenuItemIcon<&bobbyicons::update>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILDSERVERMENU>, SwitchScreenAction<SelectBuildServerMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_REDOWNLOAD>, RedownloadJsonAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
void OtaMenu::back()
|
||||
{
|
||||
switchScreen<MainMenu>();
|
||||
}
|
@ -1,40 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
// 3rdparty lib includes
|
||||
#include "menudisplay.h"
|
||||
#include "actioninterface.h"
|
||||
#include "utils.h"
|
||||
#include "actions/dummyaction.h"
|
||||
#include "icons/back.h"
|
||||
#include "icons/update.h"
|
||||
#include "icons/presets.h"
|
||||
|
||||
// local includes
|
||||
#include "texts.h"
|
||||
#include "buildserver.h"
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
namespace {
|
||||
|
||||
class RedownloadJsonAction : public virtual ActionInterface {
|
||||
public:
|
||||
void triggered() override {
|
||||
redownload = true;
|
||||
}
|
||||
};
|
||||
|
||||
class OtaMenu :
|
||||
public MenuDisplay,
|
||||
public StaticText<TEXT_UPDATE>,
|
||||
public BackActionInterface<SwitchScreenAction<MainMenu>>
|
||||
public espgui::MenuDisplay,
|
||||
public espgui::StaticText<TEXT_UPDATE>
|
||||
{
|
||||
public:
|
||||
OtaMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILD>, SwitchScreenAction<SelectBuildMenu>, StaticMenuItemIcon<&bobbyicons::presets>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_UPDATENOW>, SwitchScreenAction<UpdateDisplay>, StaticMenuItemIcon<&bobbyicons::update>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILDSERVERMENU>, SwitchScreenAction<SelectBuildServerMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_REDOWNLOAD>, RedownloadJsonAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
OtaMenu();
|
||||
|
||||
void back() override;
|
||||
};
|
||||
} // namespace
|
||||
|
0
main/displays/menus/selectotabuildmenu.cpp
Normal file
0
main/displays/menus/selectotabuildmenu.cpp
Normal file
@ -18,11 +18,6 @@
|
||||
|
||||
#define MESSAGE(text) constructMenuItem<makeComponent<MenuItem, StaticText<text>, DefaultFont, StaticColor<TFT_RED>, DummyAction>>()
|
||||
|
||||
// forward declares
|
||||
namespace {
|
||||
class OtaMenu;
|
||||
} // namespace
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
namespace {
|
||||
|
@ -0,0 +1,175 @@
|
||||
#include "pingpongdisplay.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
#include <tftinstance.h>
|
||||
#include <screenmanager.h>
|
||||
|
||||
// local includes
|
||||
#include "displays/menus/demosmenu.h"
|
||||
|
||||
PingPongDisplay::PingPongDisplay() :
|
||||
lpaddle_y(cpputils::randomNumber<uint8_t>(0, h - paddle_h, espcpputils::esp_random_device{})),
|
||||
rpaddle_y(cpputils::randomNumber<uint8_t>(0, h - paddle_h, espcpputils::esp_random_device{})),
|
||||
// ball is placed on the center of the left paddle
|
||||
ball_y(lpaddle_y + (paddle_h / 2))
|
||||
{
|
||||
calc_target_y();
|
||||
}
|
||||
|
||||
void PingPongDisplay::initScreen()
|
||||
{
|
||||
espgui::tft.fillScreen(TFT_BLACK);
|
||||
espgui::tft.setRotation(1);
|
||||
|
||||
midline();
|
||||
}
|
||||
|
||||
void PingPongDisplay::redraw()
|
||||
{
|
||||
lpaddle();
|
||||
rpaddle();
|
||||
|
||||
midline();
|
||||
|
||||
ball();
|
||||
}
|
||||
|
||||
void PingPongDisplay::stop()
|
||||
{
|
||||
espgui::tft.setRotation(0);
|
||||
}
|
||||
|
||||
void PingPongDisplay::confirm()
|
||||
{
|
||||
espgui::switchScreen<DemosMenu>();
|
||||
}
|
||||
|
||||
void PingPongDisplay::back()
|
||||
{
|
||||
espgui::switchScreen<DemosMenu>();
|
||||
}
|
||||
|
||||
void PingPongDisplay::midline()
|
||||
{
|
||||
// If the ball is not on the line then don't redraw the line
|
||||
if ((ball_x<dashline_x-ball_w) && (ball_x > dashline_x+dashline_w)) return;
|
||||
|
||||
espgui::tft.startWrite();
|
||||
|
||||
// Quick way to draw a dashed line
|
||||
espgui::tft.setAddrWindow(dashline_x, 0, dashline_w, h);
|
||||
|
||||
for (int16_t i = 0; i < dashline_n; i+=2)
|
||||
{
|
||||
espgui::tft.pushColor(WHITE, dashline_w*dashline_h); // push dash pixels
|
||||
espgui::tft.pushColor(BLACK, dashline_w*dashline_h); // push gap pixels
|
||||
}
|
||||
|
||||
espgui::tft.endWrite();
|
||||
}
|
||||
|
||||
void PingPongDisplay::lpaddle()
|
||||
{
|
||||
if (lpaddle_d == 1)
|
||||
{
|
||||
espgui::tft.fillRect(lpaddle_x, lpaddle_y, paddle_w, 1, BLACK);
|
||||
}
|
||||
else if (lpaddle_d == -1)
|
||||
{
|
||||
espgui::tft.fillRect(lpaddle_x, lpaddle_y + paddle_h - 1, paddle_w, 1, BLACK);
|
||||
}
|
||||
|
||||
lpaddle_y = lpaddle_y + lpaddle_d;
|
||||
|
||||
if (ball_dx == 1)
|
||||
lpaddle_d = 0;
|
||||
else
|
||||
{
|
||||
if (lpaddle_y + paddle_h / 2 == target_y) lpaddle_d = 0;
|
||||
else if (lpaddle_y + paddle_h / 2 > target_y) lpaddle_d = -1;
|
||||
else lpaddle_d = 1;
|
||||
}
|
||||
|
||||
if (lpaddle_y + paddle_h >= h && lpaddle_d == 1) lpaddle_d = 0;
|
||||
else if (lpaddle_y <= 0 && lpaddle_d == -1) lpaddle_d = 0;
|
||||
|
||||
espgui::tft.fillRect(lpaddle_x, lpaddle_y, paddle_w, paddle_h, WHITE);
|
||||
}
|
||||
|
||||
void PingPongDisplay::rpaddle()
|
||||
{
|
||||
if (rpaddle_d == 1)
|
||||
espgui::tft.fillRect(rpaddle_x, rpaddle_y, paddle_w, 1, BLACK);
|
||||
else if (rpaddle_d == -1)
|
||||
espgui::tft.fillRect(rpaddle_x, rpaddle_y + paddle_h - 1, paddle_w, 1, BLACK);
|
||||
|
||||
rpaddle_y = rpaddle_y + rpaddle_d;
|
||||
|
||||
if (ball_dx == -1)
|
||||
rpaddle_d = 0;
|
||||
else
|
||||
{
|
||||
if (rpaddle_y + paddle_h / 2 == target_y) rpaddle_d = 0;
|
||||
else if (rpaddle_y + paddle_h / 2 > target_y) rpaddle_d = -1;
|
||||
else rpaddle_d = 1;
|
||||
}
|
||||
|
||||
if (rpaddle_y + paddle_h >= h && rpaddle_d == 1)
|
||||
rpaddle_d = 0;
|
||||
else if (rpaddle_y <= 0 && rpaddle_d == -1)
|
||||
rpaddle_d = 0;
|
||||
|
||||
espgui::tft.fillRect(rpaddle_x, rpaddle_y, paddle_w, paddle_h, WHITE);
|
||||
}
|
||||
|
||||
void PingPongDisplay::calc_target_y()
|
||||
{
|
||||
int16_t target_x;
|
||||
int16_t reflections;
|
||||
int16_t y;
|
||||
|
||||
if (ball_dx == 1)
|
||||
target_x = w - ball_w;
|
||||
else
|
||||
target_x = -1 * (w - ball_w);
|
||||
|
||||
y = abs(target_x * (ball_dy / ball_dx) + ball_y);
|
||||
|
||||
reflections = floor(y / h);
|
||||
|
||||
if (reflections % 2 == 0)
|
||||
target_y = y % h;
|
||||
else
|
||||
target_y = h - (y % h);
|
||||
}
|
||||
|
||||
void PingPongDisplay::ball()
|
||||
{
|
||||
ball_x = ball_x + ball_dx;
|
||||
ball_y = ball_y + ball_dy;
|
||||
|
||||
if (ball_dx == -1 && ball_x == paddle_w && ball_y + ball_h >= lpaddle_y && ball_y <= lpaddle_y + paddle_h) {
|
||||
ball_dx = ball_dx * -1;
|
||||
dly = cpputils::randomNumber<uint8_t>(5, espcpputils::esp_random_device{}); // change speed of ball after paddle contact
|
||||
calc_target_y();
|
||||
} else if (ball_dx == 1 && ball_x + ball_w == w - paddle_w && ball_y + ball_h >= rpaddle_y && ball_y <= rpaddle_y + paddle_h) {
|
||||
ball_dx = ball_dx * -1;
|
||||
dly = cpputils::randomNumber<uint8_t>(5, espcpputils::esp_random_device{}); // change speed of ball after paddle contact
|
||||
calc_target_y();
|
||||
} else if ((ball_dx == 1 && ball_x >= w) || (ball_dx == -1 && ball_x + ball_w < 0)) {
|
||||
dly = 5;
|
||||
}
|
||||
|
||||
if (ball_y > h - ball_w || ball_y < 0) {
|
||||
ball_dy = ball_dy * -1;
|
||||
ball_y += ball_dy; // Keep in bounds
|
||||
}
|
||||
|
||||
//tft.fillRect(oldball_x, oldball_y, ball_w, ball_h, BLACK);
|
||||
espgui::tft.drawRect(oldball_x, oldball_y, ball_w, ball_h, BLACK); // Less TFT refresh aliasing than line above for large balls
|
||||
espgui::tft.fillRect( ball_x, ball_y, ball_w, ball_h, WHITE);
|
||||
oldball_x = ball_x;
|
||||
oldball_y = ball_y;
|
||||
}
|
||||
|
@ -4,15 +4,9 @@
|
||||
#include <cstdint>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
|
||||
// local includes
|
||||
#include "display.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
|
||||
namespace {
|
||||
class PingPongDisplay : public Display, public ConfirmActionInterface<SwitchScreenAction<DemosMenu>>, public BackActionInterface<SwitchScreenAction<DemosMenu>>
|
||||
class PingPongDisplay : public espgui::Display
|
||||
{
|
||||
public:
|
||||
PingPongDisplay();
|
||||
@ -21,6 +15,9 @@ public:
|
||||
void redraw() override;
|
||||
void stop() override;
|
||||
|
||||
void confirm() override;
|
||||
void back() override;
|
||||
|
||||
private:
|
||||
void midline();
|
||||
void lpaddle();
|
||||
@ -74,160 +71,3 @@ private:
|
||||
static const constexpr auto WHITE = 0xFFFF;
|
||||
static const constexpr auto GREY = 0x5AEB;
|
||||
};
|
||||
|
||||
PingPongDisplay::PingPongDisplay() :
|
||||
lpaddle_y(cpputils::randomNumber<uint8_t>(0, h - paddle_h, espcpputils::esp_random_device{})),
|
||||
rpaddle_y(cpputils::randomNumber<uint8_t>(0, h - paddle_h, espcpputils::esp_random_device{})),
|
||||
// ball is placed on the center of the left paddle
|
||||
ball_y(lpaddle_y + (paddle_h / 2))
|
||||
{
|
||||
calc_target_y();
|
||||
}
|
||||
|
||||
void PingPongDisplay::initScreen()
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setRotation(1);
|
||||
|
||||
midline();
|
||||
}
|
||||
|
||||
void PingPongDisplay::redraw()
|
||||
{
|
||||
lpaddle();
|
||||
rpaddle();
|
||||
|
||||
midline();
|
||||
|
||||
ball();
|
||||
}
|
||||
|
||||
void PingPongDisplay::stop()
|
||||
{
|
||||
tft.setRotation(0);
|
||||
}
|
||||
|
||||
void PingPongDisplay::midline()
|
||||
{
|
||||
// If the ball is not on the line then don't redraw the line
|
||||
if ((ball_x<dashline_x-ball_w) && (ball_x > dashline_x+dashline_w)) return;
|
||||
|
||||
tft.startWrite();
|
||||
|
||||
// Quick way to draw a dashed line
|
||||
tft.setAddrWindow(dashline_x, 0, dashline_w, h);
|
||||
|
||||
for(int16_t i = 0; i < dashline_n; i+=2) {
|
||||
tft.pushColor(WHITE, dashline_w*dashline_h); // push dash pixels
|
||||
tft.pushColor(BLACK, dashline_w*dashline_h); // push gap pixels
|
||||
}
|
||||
|
||||
tft.endWrite();
|
||||
}
|
||||
|
||||
void PingPongDisplay::lpaddle()
|
||||
{
|
||||
if (lpaddle_d == 1)
|
||||
{
|
||||
tft.fillRect(lpaddle_x, lpaddle_y, paddle_w, 1, BLACK);
|
||||
}
|
||||
else if (lpaddle_d == -1)
|
||||
{
|
||||
tft.fillRect(lpaddle_x, lpaddle_y + paddle_h - 1, paddle_w, 1, BLACK);
|
||||
}
|
||||
|
||||
lpaddle_y = lpaddle_y + lpaddle_d;
|
||||
|
||||
if (ball_dx == 1)
|
||||
lpaddle_d = 0;
|
||||
else
|
||||
{
|
||||
if (lpaddle_y + paddle_h / 2 == target_y) lpaddle_d = 0;
|
||||
else if (lpaddle_y + paddle_h / 2 > target_y) lpaddle_d = -1;
|
||||
else lpaddle_d = 1;
|
||||
}
|
||||
|
||||
if (lpaddle_y + paddle_h >= h && lpaddle_d == 1) lpaddle_d = 0;
|
||||
else if (lpaddle_y <= 0 && lpaddle_d == -1) lpaddle_d = 0;
|
||||
|
||||
tft.fillRect(lpaddle_x, lpaddle_y, paddle_w, paddle_h, WHITE);
|
||||
}
|
||||
|
||||
void PingPongDisplay::rpaddle()
|
||||
{
|
||||
if (rpaddle_d == 1) {
|
||||
tft.fillRect(rpaddle_x, rpaddle_y, paddle_w, 1, BLACK);
|
||||
}
|
||||
else if (rpaddle_d == -1) {
|
||||
tft.fillRect(rpaddle_x, rpaddle_y + paddle_h - 1, paddle_w, 1, BLACK);
|
||||
}
|
||||
|
||||
rpaddle_y = rpaddle_y + rpaddle_d;
|
||||
|
||||
if (ball_dx == -1) rpaddle_d = 0;
|
||||
else {
|
||||
if (rpaddle_y + paddle_h / 2 == target_y) rpaddle_d = 0;
|
||||
else if (rpaddle_y + paddle_h / 2 > target_y) rpaddle_d = -1;
|
||||
else rpaddle_d = 1;
|
||||
}
|
||||
|
||||
if (rpaddle_y + paddle_h >= h && rpaddle_d == 1) rpaddle_d = 0;
|
||||
else if (rpaddle_y <= 0 && rpaddle_d == -1) rpaddle_d = 0;
|
||||
|
||||
tft.fillRect(rpaddle_x, rpaddle_y, paddle_w, paddle_h, WHITE);
|
||||
}
|
||||
|
||||
void PingPongDisplay::calc_target_y()
|
||||
{
|
||||
int16_t target_x;
|
||||
int16_t reflections;
|
||||
int16_t y;
|
||||
|
||||
if (ball_dx == 1) {
|
||||
target_x = w - ball_w;
|
||||
}
|
||||
else {
|
||||
target_x = -1 * (w - ball_w);
|
||||
}
|
||||
|
||||
y = abs(target_x * (ball_dy / ball_dx) + ball_y);
|
||||
|
||||
reflections = floor(y / h);
|
||||
|
||||
if (reflections % 2 == 0) {
|
||||
target_y = y % h;
|
||||
}
|
||||
else {
|
||||
target_y = h - (y % h);
|
||||
}
|
||||
}
|
||||
|
||||
void PingPongDisplay::ball()
|
||||
{
|
||||
ball_x = ball_x + ball_dx;
|
||||
ball_y = ball_y + ball_dy;
|
||||
|
||||
if (ball_dx == -1 && ball_x == paddle_w && ball_y + ball_h >= lpaddle_y && ball_y <= lpaddle_y + paddle_h) {
|
||||
ball_dx = ball_dx * -1;
|
||||
dly = cpputils::randomNumber<uint8_t>(5, espcpputils::esp_random_device{}); // change speed of ball after paddle contact
|
||||
calc_target_y();
|
||||
} else if (ball_dx == 1 && ball_x + ball_w == w - paddle_w && ball_y + ball_h >= rpaddle_y && ball_y <= rpaddle_y + paddle_h) {
|
||||
ball_dx = ball_dx * -1;
|
||||
dly = cpputils::randomNumber<uint8_t>(5, espcpputils::esp_random_device{}); // change speed of ball after paddle contact
|
||||
calc_target_y();
|
||||
} else if ((ball_dx == 1 && ball_x >= w) || (ball_dx == -1 && ball_x + ball_w < 0)) {
|
||||
dly = 5;
|
||||
}
|
||||
|
||||
if (ball_y > h - ball_w || ball_y < 0) {
|
||||
ball_dy = ball_dy * -1;
|
||||
ball_y += ball_dy; // Keep in bounds
|
||||
}
|
||||
|
||||
//tft.fillRect(oldball_x, oldball_y, ball_w, ball_h, BLACK);
|
||||
tft.drawRect(oldball_x, oldball_y, ball_w, ball_h, BLACK); // Less TFT refresh aliasing than line above for large balls
|
||||
tft.fillRect( ball_x, ball_y, ball_w, ball_h, WHITE);
|
||||
oldball_x = ball_x;
|
||||
oldball_y = ball_y;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,120 @@
|
||||
#include "spirodisplay.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
#include <tftinstance.h>
|
||||
#include <screenmanager.h>
|
||||
|
||||
// local includes
|
||||
#include "displays/menus/demosmenu.h"
|
||||
|
||||
void SpiroDisplay::initScreen()
|
||||
{
|
||||
Base::initScreen();
|
||||
espgui::tft.setRotation(3);
|
||||
}
|
||||
|
||||
void SpiroDisplay::redraw()
|
||||
{
|
||||
for (int j = 0; j < std::max(1, n); j++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
espgui::tft.fillScreen(TFT_BLACK);
|
||||
n = cpputils::randomNumber<uint8_t>(2, 23, espcpputils::esp_random_device{});
|
||||
r = cpputils::randomNumber<uint8_t>(20, 100, espcpputils::esp_random_device{});
|
||||
colour = 0; //rainbow();
|
||||
}
|
||||
|
||||
if (i < (360 * n))
|
||||
{
|
||||
sx = std::cos((i / n - 90) * DEG2RAD);
|
||||
sy = std::sin((i / n - 90) * DEG2RAD);
|
||||
x0 = sx * (120 - r) + 159;
|
||||
yy0 = sy * (120 - r) + 119;
|
||||
|
||||
|
||||
sy = std::cos(((i % 360) - 90) * DEG2RAD);
|
||||
sx = std::sin(((i % 360) - 90) * DEG2RAD);
|
||||
x1 = sx * r + x0;
|
||||
yy1 = sy * r + yy0;
|
||||
espgui::tft.drawPixel(x1, yy1, rainbow(map(i%360,0,360,0,127))); //colour);
|
||||
}
|
||||
|
||||
if (i == (360 * n))
|
||||
{
|
||||
r = cpputils::randomNumber<uint8_t>(20, 100, espcpputils::esp_random_device{});//r = r / random(2,4);
|
||||
}
|
||||
|
||||
if (i >= (360 * n))
|
||||
{
|
||||
auto new_i = i - (360 * n);
|
||||
|
||||
sx = std::cos((new_i / n - 90) * DEG2RAD);
|
||||
sy = std::sin((new_i / n - 90) * DEG2RAD);
|
||||
x0 = sx * (120 - r) + 159;
|
||||
yy0 = sy * (120 - r) + 119;
|
||||
|
||||
|
||||
sy = std::cos(((new_i % 360) - 90) * DEG2RAD);
|
||||
sx = std::sin(((new_i % 360) - 90) * DEG2RAD);
|
||||
x1 = sx * r + x0;
|
||||
yy1 = sy * r + yy0;
|
||||
espgui::tft.drawPixel(x1, yy1, rainbow(map(new_i%360,0,360,0,127))); //colour);
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i == 2* (360 * n))
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SpiroDisplay::stop()
|
||||
{
|
||||
espgui::tft.setRotation(0);
|
||||
}
|
||||
|
||||
unsigned int SpiroDisplay::rainbow(int value)
|
||||
{
|
||||
// Value is expected to be in range 0-127
|
||||
// The value is converted to a spectrum colour from 0 = blue through to red = blue
|
||||
//int value = random (128);
|
||||
byte red = 0; // Red is the top 5 bits of a 16 bit colour value
|
||||
byte green = 0;// Green is the middle 6 bits
|
||||
byte blue = 0; // Blue is the bottom 5 bits
|
||||
|
||||
byte quadrant = value / 32;
|
||||
|
||||
if (quadrant == 0) {
|
||||
blue = 31;
|
||||
green = 2 * (value % 32);
|
||||
red = 0;
|
||||
}
|
||||
if (quadrant == 1) {
|
||||
blue = 31 - (value % 32);
|
||||
green = 63;
|
||||
red = 0;
|
||||
}
|
||||
if (quadrant == 2) {
|
||||
blue = 0;
|
||||
green = 63;
|
||||
red = value % 32;
|
||||
}
|
||||
if (quadrant == 3) {
|
||||
blue = 0;
|
||||
green = 63 - 2 * (value % 32);
|
||||
red = 31;
|
||||
}
|
||||
return (red << 11) + (green << 5) + blue;
|
||||
}
|
||||
|
||||
void SpiroDisplay::confirm()
|
||||
{
|
||||
espgui::switchScreen<DemosMenu>();
|
||||
}
|
||||
|
||||
void SpiroDisplay::back()
|
||||
{
|
||||
espgui::switchScreen<DemosMenu>();
|
||||
}
|
||||
|
@ -3,22 +3,22 @@
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
|
||||
// local includes
|
||||
#include "display.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
|
||||
namespace {
|
||||
class SpiroDisplay : public Display, public DummyConfirm, public BackActionInterface<SwitchScreenAction<DemosMenu>>
|
||||
class SpiroDisplay : public espgui::Display
|
||||
{
|
||||
using Base = espgui::Display;
|
||||
|
||||
public:
|
||||
void initScreen() override;
|
||||
void redraw() override;
|
||||
void stop() override;
|
||||
|
||||
void confirm() override;
|
||||
void back() override;
|
||||
|
||||
private:
|
||||
constexpr static auto DEG2RAD = 0.0174532925;
|
||||
|
||||
@ -30,104 +30,3 @@ private:
|
||||
long i{0};
|
||||
int n{}, r{}, colour{};
|
||||
};
|
||||
|
||||
void SpiroDisplay::initScreen()
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setRotation(3);
|
||||
}
|
||||
|
||||
void SpiroDisplay::redraw()
|
||||
{
|
||||
for (int j = 0; j < std::max(1, n); j++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
n = cpputils::randomNumber<uint8_t>(2, 23, espcpputils::esp_random_device{});
|
||||
r = cpputils::randomNumber<uint8_t>(20, 100, espcpputils::esp_random_device{});
|
||||
colour = 0; //rainbow();
|
||||
}
|
||||
|
||||
if (i < (360 * n))
|
||||
{
|
||||
sx = std::cos((i / n - 90) * DEG2RAD);
|
||||
sy = std::sin((i / n - 90) * DEG2RAD);
|
||||
x0 = sx * (120 - r) + 159;
|
||||
yy0 = sy * (120 - r) + 119;
|
||||
|
||||
|
||||
sy = std::cos(((i % 360) - 90) * DEG2RAD);
|
||||
sx = std::sin(((i % 360) - 90) * DEG2RAD);
|
||||
x1 = sx * r + x0;
|
||||
yy1 = sy * r + yy0;
|
||||
tft.drawPixel(x1, yy1, rainbow(map(i%360,0,360,0,127))); //colour);
|
||||
}
|
||||
|
||||
if (i == (360 * n))
|
||||
{
|
||||
r = cpputils::randomNumber<uint8_t>(20, 100, espcpputils::esp_random_device{});//r = r / random(2,4);
|
||||
}
|
||||
|
||||
if (i >= (360 * n))
|
||||
{
|
||||
auto new_i = i - (360 * n);
|
||||
|
||||
sx = std::cos((new_i / n - 90) * DEG2RAD);
|
||||
sy = std::sin((new_i / n - 90) * DEG2RAD);
|
||||
x0 = sx * (120 - r) + 159;
|
||||
yy0 = sy * (120 - r) + 119;
|
||||
|
||||
|
||||
sy = std::cos(((new_i % 360) - 90) * DEG2RAD);
|
||||
sx = std::sin(((new_i % 360) - 90) * DEG2RAD);
|
||||
x1 = sx * r + x0;
|
||||
yy1 = sy * r + yy0;
|
||||
tft.drawPixel(x1, yy1, rainbow(map(new_i%360,0,360,0,127))); //colour);
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i == 2* (360 * n))
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SpiroDisplay::stop()
|
||||
{
|
||||
tft.setRotation(0);
|
||||
}
|
||||
|
||||
unsigned int SpiroDisplay::rainbow(int value)
|
||||
{
|
||||
// Value is expected to be in range 0-127
|
||||
// The value is converted to a spectrum colour from 0 = blue through to red = blue
|
||||
//int value = random (128);
|
||||
byte red = 0; // Red is the top 5 bits of a 16 bit colour value
|
||||
byte green = 0;// Green is the middle 6 bits
|
||||
byte blue = 0; // Blue is the bottom 5 bits
|
||||
|
||||
byte quadrant = value / 32;
|
||||
|
||||
if (quadrant == 0) {
|
||||
blue = 31;
|
||||
green = 2 * (value % 32);
|
||||
red = 0;
|
||||
}
|
||||
if (quadrant == 1) {
|
||||
blue = 31 - (value % 32);
|
||||
green = 63;
|
||||
red = 0;
|
||||
}
|
||||
if (quadrant == 2) {
|
||||
blue = 0;
|
||||
green = 63;
|
||||
red = value % 32;
|
||||
}
|
||||
if (quadrant == 3) {
|
||||
blue = 0;
|
||||
green = 63 - 2 * (value % 32);
|
||||
red = 31;
|
||||
}
|
||||
return (red << 11) + (green << 5) + blue;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,114 @@
|
||||
#include "updatedisplay.h"
|
||||
|
||||
// system includes
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <tftinstance.h>
|
||||
#include <screenmanager.h>
|
||||
#ifdef FEATURE_OTA
|
||||
#include <espasyncota.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
// local includes
|
||||
#include "globals.h"
|
||||
#include "texts.h"
|
||||
#include "ota.h"
|
||||
#include "displays/menus/otamenu.h"
|
||||
|
||||
#ifdef FEATURE_OTA
|
||||
void UpdateDisplay::initScreen()
|
||||
{
|
||||
Base::initScreen();
|
||||
|
||||
espgui::tft.setTextFont(4);
|
||||
espgui::tft.setTextColor(TFT_YELLOW);
|
||||
|
||||
espgui::tft.drawString(TEXT_UPDATE, 5, 5, 4);
|
||||
|
||||
espgui::tft.fillRect(0, 34, espgui::tft.width(), 3, TFT_WHITE);
|
||||
|
||||
espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
|
||||
espgui::tft.drawString("Status:", 20, m_statusLabel.y());
|
||||
m_statusLabel.start();
|
||||
|
||||
espgui::tft.drawString("Progress:", 20, m_progressLabel.y());
|
||||
m_progressLabel.start();
|
||||
|
||||
espgui::tft.drawString("Total:", 20, m_totalLabel.y());
|
||||
m_totalLabel.start();
|
||||
|
||||
m_messageLabel.start();
|
||||
|
||||
m_progressBar.start();
|
||||
|
||||
if (const esp_app_desc_t *app_desc = esp_ota_get_app_description())
|
||||
{
|
||||
espgui::tft.setTextColor(TFT_ORANGE, TFT_BLACK);
|
||||
espgui::tft.drawString(app_desc->version, 20, 250);
|
||||
espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
}
|
||||
|
||||
m_newVersionLabel.start();
|
||||
}
|
||||
|
||||
void UpdateDisplay::redraw()
|
||||
{
|
||||
Base::redraw();
|
||||
|
||||
if (asyncOta)
|
||||
{
|
||||
m_statusLabel.redraw(toString(asyncOta->status()));
|
||||
const auto progress = asyncOta->progress();
|
||||
m_progressLabel.redraw(std::to_string(progress));
|
||||
if (const auto totalSize = asyncOta->totalSize(); totalSize && *totalSize > 0)
|
||||
{
|
||||
m_totalLabel.redraw(std::to_string(*totalSize));
|
||||
m_progressBar.redraw(float(progress) / *totalSize * 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_totalLabel.clear();
|
||||
m_progressBar.redraw(0);
|
||||
}
|
||||
m_messageLabel.redraw(asyncOta->message());
|
||||
|
||||
if (const auto &appDesc = asyncOta->appDesc())
|
||||
{
|
||||
espgui::tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||
m_newVersionLabel.redraw(appDesc->version);
|
||||
espgui::tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
}
|
||||
else
|
||||
m_newVersionLabel.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_statusLabel.clear();
|
||||
m_progressLabel.clear();
|
||||
m_totalLabel.clear();
|
||||
m_messageLabel.clear();
|
||||
|
||||
m_progressBar.redraw(0);
|
||||
|
||||
m_newVersionLabel.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateDisplay::confirm()
|
||||
{
|
||||
if (const auto result = triggerOta(stringSettings.otaUrl); !result)
|
||||
ESP_LOGE("BOBBY", "triggerOta() failed with %.*s", result.error().size(), result.error().data());
|
||||
}
|
||||
|
||||
void UpdateDisplay::back()
|
||||
{
|
||||
espgui::switchScreen<OtaMenu>();
|
||||
}
|
||||
#endif
|
||||
|
@ -1,136 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#ifdef FEATURE_OTA
|
||||
#include <espasyncota.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#endif
|
||||
|
||||
// local includes
|
||||
#include "display.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
#include "globals.h"
|
||||
#include "texts.h"
|
||||
#include "widgets/label.h"
|
||||
#include "widgets/progressbar.h"
|
||||
#include "ota.h"
|
||||
|
||||
namespace {
|
||||
class OtaMenu;
|
||||
}
|
||||
|
||||
namespace {
|
||||
#ifdef FEATURE_OTA
|
||||
class UpdateDisplay : public Display, public BackActionInterface<SwitchScreenAction<OtaMenu>>
|
||||
class UpdateDisplay : public espgui::Display
|
||||
{
|
||||
using Base = espgui::Display;
|
||||
public:
|
||||
void start() override;
|
||||
void initScreen() override;
|
||||
void redraw() override;
|
||||
void confirm() override;
|
||||
void back() override;
|
||||
|
||||
private:
|
||||
Label m_statusLabel{120, 75};
|
||||
Label m_progressLabel{120, 100};
|
||||
Label m_totalLabel{120, 125};
|
||||
Label m_messageLabel{20, 150};
|
||||
espgui::Label m_statusLabel{120, 75};
|
||||
espgui::Label m_progressLabel{120, 100};
|
||||
espgui::Label m_totalLabel{120, 125};
|
||||
espgui::Label m_messageLabel{20, 150};
|
||||
|
||||
ProgressBar m_progressBar{20, 200, 200, 10, 0, 100};
|
||||
espgui::ProgressBar m_progressBar{20, 200, 200, 10, 0, 100};
|
||||
|
||||
Label m_newVersionLabel{20, 275};
|
||||
espgui::Label m_newVersionLabel{20, 275};
|
||||
};
|
||||
|
||||
void UpdateDisplay::start()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateDisplay::initScreen()
|
||||
{
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setTextFont(4);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
|
||||
tft.drawString(TEXT_UPDATE, 5, 5, 4);
|
||||
|
||||
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
|
||||
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
|
||||
tft.drawString("Status:", 20, m_statusLabel.y());
|
||||
m_statusLabel.start();
|
||||
|
||||
tft.drawString("Progress:", 20, m_progressLabel.y());
|
||||
m_progressLabel.start();
|
||||
|
||||
tft.drawString("Total:", 20, m_totalLabel.y());
|
||||
m_totalLabel.start();
|
||||
|
||||
m_messageLabel.start();
|
||||
|
||||
m_progressBar.start();
|
||||
|
||||
if (const esp_app_desc_t *app_desc = esp_ota_get_app_description())
|
||||
{
|
||||
tft.setTextColor(TFT_ORANGE, TFT_BLACK);
|
||||
tft.drawString(app_desc->version, 20, 250);
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
}
|
||||
|
||||
m_newVersionLabel.start();
|
||||
}
|
||||
|
||||
void UpdateDisplay::redraw()
|
||||
{
|
||||
if (asyncOta)
|
||||
{
|
||||
m_statusLabel.redraw(toString(asyncOta->status()));
|
||||
const auto progress = asyncOta->progress();
|
||||
m_progressLabel.redraw(std::to_string(progress));
|
||||
if (const auto totalSize = asyncOta->totalSize(); totalSize && *totalSize > 0)
|
||||
{
|
||||
m_totalLabel.redraw(std::to_string(*totalSize));
|
||||
m_progressBar.redraw(float(progress) / *totalSize * 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_totalLabel.clear();
|
||||
m_progressBar.redraw(0);
|
||||
}
|
||||
m_messageLabel.redraw(asyncOta->message());
|
||||
|
||||
if (const auto &appDesc = asyncOta->appDesc())
|
||||
{
|
||||
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||
m_newVersionLabel.redraw(appDesc->version);
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
}
|
||||
else
|
||||
m_newVersionLabel.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_statusLabel.clear();
|
||||
m_progressLabel.clear();
|
||||
m_totalLabel.clear();
|
||||
m_messageLabel.clear();
|
||||
|
||||
m_progressBar.redraw(0);
|
||||
|
||||
m_newVersionLabel.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateDisplay::confirm()
|
||||
{
|
||||
if (const auto result = triggerOta(stringSettings.otaUrl); !result)
|
||||
ESP_LOGE("BOBBY", "triggerOta() failed with %.*s", result.error().size(), result.error().data());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
52
main/ota.cpp
52
main/ota.cpp
@ -0,0 +1,52 @@
|
||||
#include "ota.h"
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <espwifistack.h>
|
||||
|
||||
#ifdef FEATURE_OTA
|
||||
extern cpputils::DelayedConstruction<EspAsyncOta> asyncOta;
|
||||
extern bool asyncOtaTaskStarted;
|
||||
|
||||
namespace {
|
||||
constexpr const char * const TAG = "BOBBYOTA";
|
||||
} // namespace
|
||||
|
||||
void initOta()
|
||||
{
|
||||
}
|
||||
|
||||
void handleOta()
|
||||
{
|
||||
if (asyncOta)
|
||||
asyncOta->update();
|
||||
}
|
||||
|
||||
tl::expected<void, std::string> triggerOta(std::string_view url)
|
||||
{
|
||||
ESP_LOGI(TAG, "%.*s", url.size(), url.data());
|
||||
|
||||
if (!asyncOta)
|
||||
asyncOta.construct();
|
||||
|
||||
if (!asyncOtaTaskStarted)
|
||||
{
|
||||
if (const auto result = asyncOta->startTask(); !result)
|
||||
{
|
||||
ESP_LOGE(TAG, "starting OTA task failed: %.*s", result.error().size(), result.error().data());
|
||||
return tl::make_unexpected(fmt::format("starting OTA task failed: {}", result.error()));
|
||||
}
|
||||
|
||||
asyncOtaTaskStarted = true;
|
||||
}
|
||||
|
||||
if (const auto result = asyncOta->trigger(url, {}, {}, {}); !result)
|
||||
return tl::make_unexpected(std::move(result).error());
|
||||
|
||||
wifi_stack::delete_scan_result();
|
||||
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
40
main/ota.h
40
main/ota.h
@ -8,45 +8,11 @@
|
||||
|
||||
// local includes
|
||||
|
||||
namespace {
|
||||
#ifdef FEATURE_OTA
|
||||
cpputils::DelayedConstruction<EspAsyncOta> asyncOta;
|
||||
bool asyncOtaTaskStarted{};
|
||||
|
||||
void initOta()
|
||||
{
|
||||
}
|
||||
|
||||
void handleOta()
|
||||
{
|
||||
if (asyncOta)
|
||||
asyncOta->update();
|
||||
}
|
||||
|
||||
tl::expected<void, std::string> triggerOta(std::string_view url)
|
||||
{
|
||||
ESP_LOGI(TAG, "%.*s", url.size(), url.data());
|
||||
|
||||
if (!asyncOta)
|
||||
asyncOta.construct();
|
||||
|
||||
if (!asyncOtaTaskStarted)
|
||||
{
|
||||
if (const auto result = asyncOta->startTask(); !result)
|
||||
{
|
||||
ESP_LOGE(TAG, "starting OTA task failed: %.*s", result.error().size(), result.error().data());
|
||||
return tl::make_unexpected(fmt::format("starting OTA task failed: {}", result.error()));
|
||||
}
|
||||
|
||||
asyncOtaTaskStarted = true;
|
||||
}
|
||||
|
||||
if (const auto result = asyncOta->trigger(url, {}, {}, {}); !result)
|
||||
return tl::make_unexpected(std::move(result).error());
|
||||
|
||||
wifi_stack::delete_scan_result();
|
||||
|
||||
return {};
|
||||
}
|
||||
void initOta();
|
||||
void handleOta();
|
||||
tl::expected<void, std::string> triggerOta(std::string_view url);
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user