More refactorings again
This commit is contained in:
@ -311,6 +311,8 @@ set(sources
|
|||||||
displays/menus/mosfetsmenu.cpp
|
displays/menus/mosfetsmenu.cpp
|
||||||
displays/menus/motorfeedbackdebugmenu.cpp
|
displays/menus/motorfeedbackdebugmenu.cpp
|
||||||
displays/menus/motorstatedebugmenu.cpp
|
displays/menus/motorstatedebugmenu.cpp
|
||||||
|
displays/menus/otamenu.cpp
|
||||||
|
displays/menus/selectotabuildmenu.cpp
|
||||||
displays/menus/presetsmenu.cpp
|
displays/menus/presetsmenu.cpp
|
||||||
displays/menus/profilesmenu.cpp
|
displays/menus/profilesmenu.cpp
|
||||||
displays/menus/selectbatterytypemenu.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 <bitset>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// 3rdparty lib includes
|
|
||||||
#include <randomutils.h>
|
|
||||||
#include <esprandom.h>
|
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "actions/switchscreenaction.h"
|
|
||||||
|
|
||||||
namespace {
|
class GameOfLifeDisplay : public espgui::Display
|
||||||
class GameOfLifeDisplay : public Display, public ConfirmActionInterface<SwitchScreenAction<DemosMenu>>, public BackActionInterface<SwitchScreenAction<DemosMenu>>
|
|
||||||
{
|
{
|
||||||
|
using Base = espgui::Display;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void start() override;
|
void start() override;
|
||||||
void initScreen() override;
|
void initScreen() override;
|
||||||
void redraw() override;
|
void redraw() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
|
void confirm() override;
|
||||||
|
void back() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
//Draws the grid on the display
|
//Draws the grid on the display
|
||||||
@ -71,114 +70,3 @@ private:
|
|||||||
|
|
||||||
int gen = 0;
|
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
|
#pragma once
|
||||||
|
|
||||||
// local includes
|
// 3rdparty lib includes
|
||||||
#include "menudisplay.h"
|
#include "menudisplay.h"
|
||||||
#include "actioninterface.h"
|
|
||||||
#include "utils.h"
|
// local includes
|
||||||
#include "actions/dummyaction.h"
|
|
||||||
#include "icons/back.h"
|
|
||||||
#include "icons/update.h"
|
|
||||||
#include "icons/presets.h"
|
|
||||||
#include "texts.h"
|
#include "texts.h"
|
||||||
#include "buildserver.h"
|
|
||||||
|
|
||||||
using namespace espgui;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class RedownloadJsonAction : public virtual ActionInterface {
|
|
||||||
public:
|
|
||||||
void triggered() override {
|
|
||||||
redownload = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class OtaMenu :
|
class OtaMenu :
|
||||||
public MenuDisplay,
|
public espgui::MenuDisplay,
|
||||||
public StaticText<TEXT_UPDATE>,
|
public espgui::StaticText<TEXT_UPDATE>
|
||||||
public BackActionInterface<SwitchScreenAction<MainMenu>>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OtaMenu()
|
OtaMenu();
|
||||||
{
|
|
||||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILD>, SwitchScreenAction<SelectBuildMenu>, StaticMenuItemIcon<&bobbyicons::presets>>>();
|
void back() override;
|
||||||
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>>>();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // 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>>()
|
#define MESSAGE(text) constructMenuItem<makeComponent<MenuItem, StaticText<text>, DefaultFont, StaticColor<TFT_RED>, DummyAction>>()
|
||||||
|
|
||||||
// forward declares
|
|
||||||
namespace {
|
|
||||||
class OtaMenu;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
using namespace espgui;
|
using namespace espgui;
|
||||||
|
|
||||||
namespace {
|
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>
|
#include <cstdint>
|
||||||
|
|
||||||
// 3rdparty lib includes
|
// 3rdparty lib includes
|
||||||
#include <randomutils.h>
|
|
||||||
#include <esprandom.h>
|
|
||||||
|
|
||||||
// local includes
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "actions/switchscreenaction.h"
|
|
||||||
|
|
||||||
namespace {
|
class PingPongDisplay : public espgui::Display
|
||||||
class PingPongDisplay : public Display, public ConfirmActionInterface<SwitchScreenAction<DemosMenu>>, public BackActionInterface<SwitchScreenAction<DemosMenu>>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PingPongDisplay();
|
PingPongDisplay();
|
||||||
@ -21,6 +15,9 @@ public:
|
|||||||
void redraw() override;
|
void redraw() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
|
void confirm() override;
|
||||||
|
void back() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void midline();
|
void midline();
|
||||||
void lpaddle();
|
void lpaddle();
|
||||||
@ -74,160 +71,3 @@ private:
|
|||||||
static const constexpr auto WHITE = 0xFFFF;
|
static const constexpr auto WHITE = 0xFFFF;
|
||||||
static const constexpr auto GREY = 0x5AEB;
|
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
|
// system includes
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
// 3rdparty lib includes
|
|
||||||
#include <randomutils.h>
|
|
||||||
#include <esprandom.h>
|
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "actions/switchscreenaction.h"
|
#include "actions/switchscreenaction.h"
|
||||||
|
|
||||||
namespace {
|
class SpiroDisplay : public espgui::Display
|
||||||
class SpiroDisplay : public Display, public DummyConfirm, public BackActionInterface<SwitchScreenAction<DemosMenu>>
|
|
||||||
{
|
{
|
||||||
|
using Base = espgui::Display;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void initScreen() override;
|
void initScreen() override;
|
||||||
void redraw() override;
|
void redraw() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
|
void confirm() override;
|
||||||
|
void back() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr static auto DEG2RAD = 0.0174532925;
|
constexpr static auto DEG2RAD = 0.0174532925;
|
||||||
|
|
||||||
@ -30,104 +30,3 @@ private:
|
|||||||
long i{0};
|
long i{0};
|
||||||
int n{}, r{}, colour{};
|
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
|
#pragma once
|
||||||
|
|
||||||
// system includes
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// esp-idf includes
|
|
||||||
#include <esp_log.h>
|
|
||||||
|
|
||||||
// 3rdparty lib includes
|
// 3rdparty lib includes
|
||||||
#ifdef FEATURE_OTA
|
|
||||||
#include <espasyncota.h>
|
|
||||||
#include <esp_ota_ops.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "actions/switchscreenaction.h"
|
|
||||||
#include "globals.h"
|
|
||||||
#include "texts.h"
|
|
||||||
#include "widgets/label.h"
|
#include "widgets/label.h"
|
||||||
#include "widgets/progressbar.h"
|
#include "widgets/progressbar.h"
|
||||||
#include "ota.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class OtaMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
#ifdef FEATURE_OTA
|
#ifdef FEATURE_OTA
|
||||||
class UpdateDisplay : public Display, public BackActionInterface<SwitchScreenAction<OtaMenu>>
|
class UpdateDisplay : public espgui::Display
|
||||||
{
|
{
|
||||||
|
using Base = espgui::Display;
|
||||||
public:
|
public:
|
||||||
void start() override;
|
|
||||||
void initScreen() override;
|
void initScreen() override;
|
||||||
void redraw() override;
|
void redraw() override;
|
||||||
void confirm() override;
|
void confirm() override;
|
||||||
|
void back() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Label m_statusLabel{120, 75};
|
espgui::Label m_statusLabel{120, 75};
|
||||||
Label m_progressLabel{120, 100};
|
espgui::Label m_progressLabel{120, 100};
|
||||||
Label m_totalLabel{120, 125};
|
espgui::Label m_totalLabel{120, 125};
|
||||||
Label m_messageLabel{20, 150};
|
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
|
#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
|
// local includes
|
||||||
|
|
||||||
namespace {
|
|
||||||
#ifdef FEATURE_OTA
|
#ifdef FEATURE_OTA
|
||||||
cpputils::DelayedConstruction<EspAsyncOta> asyncOta;
|
cpputils::DelayedConstruction<EspAsyncOta> asyncOta;
|
||||||
bool asyncOtaTaskStarted{};
|
bool asyncOtaTaskStarted{};
|
||||||
|
|
||||||
void initOta()
|
void initOta();
|
||||||
{
|
void handleOta();
|
||||||
}
|
tl::expected<void, std::string> triggerOta(std::string_view url);
|
||||||
|
|
||||||
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
|
#endif
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user