More refactorings again

This commit is contained in:
2021-11-02 18:33:55 +01:00
parent 8dcc898244
commit 86a7ef66ee
15 changed files with 671 additions and 577 deletions

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View 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>();
}

View File

@ -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

View 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 {

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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>();
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
}