Committed existing project

This commit is contained in:
2020-05-19 11:41:35 +02:00
parent e6df220f6e
commit 30624bfbbd
165 changed files with 11604 additions and 2 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.pio
platformio.pro*

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "bobbycar-protocol"]
path = bobbycar-protocol
path = src/bobbycar-protocol
url = git@github.com:bobbycar-graz/bobbycar-protocol.git

67
.travis.yml Normal file
View File

@ -0,0 +1,67 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

6
bobbycar.csv Normal file
View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x250000,
app1, app, ota_1, 0x260000, 0x250000,
spiffs, data, spiffs, 0x520000, 0x250000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x250000
5 app1 app ota_1 0x260000 0x250000
6 spiffs data spiffs 0x520000 0x250000

BIN
icons/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
icons/bluetooth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/buzzer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
icons/checked.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
icons/demos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
icons/graph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
icons/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
icons/lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
icons/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
icons/modes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
icons/poweroff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
icons/presets.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
icons/reboot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
icons/scan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
icons/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
icons/unchecked.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
icons/wifi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

160
platformio.ini Normal file
View File

@ -0,0 +1,160 @@
;PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:bobbycar_usb]
platform = espressif32
board = esp32dev
framework = arduino
board_build.partitions = bobbycar.csv
upload_speed = 921600
upload_port = /dev/ttyUSB*
lib_deps =
TFT_eSPI
https://github.com/Ferdi265/cxx-ring-buffer
lib_compat_mode = strict
build_unflags =
-std=gnu++11
-Os
build_flags =
-std=gnu++17
-O3
-DUSER_SETUP_LOADED=1
-DILI9341_DRIVER=1
-DTFT_MOSI=13
-DTFT_SCLK=15
-DTFT_CS=14
-DTFT_DC=12
-DTFT_RST=2
-DLOAD_GLCD=1
-DLOAD_FONT2=1
-DLOAD_FONT4=1
-DLOAD_FONT7=1
-DSPI_FREQUENCY=27000000
-DSPI_READ_FREQUENCY=20000000
-DSPI_TOUCH_FREQUENCY=2500000
-DPINS_RX1=4
-DPINS_TX1=5
-DPINS_RX2=25
-DPINS_TX2=26
-DPINS_GAS=35
-DPINS_BREMS=33
-DFEATURE_3WIRESW
-DPINS_3WIRESW_OUT=0
-DPINS_3WIRESW_IN1=16
-DPINS_3WIRESW_IN2=27
; -DFEATURE_ROTARY
; -DPINS_ROTARY_CLK=16
; -DPINS_ROTARY_DT=27
; -DPINS_ROTARY_SW=0
[env:bobbycar_ota]
platform = espressif32
board = esp32dev
framework = arduino
board_build.partitions = bobbycar.csv
upload_protocol = espota
upload_port = 192.168.127.171
lib_deps =
TFT_eSPI
https://github.com/Ferdi265/cxx-ring-buffer
lib_compat_mode = strict
build_unflags =
-std=gnu++11
-Os
build_flags =
-std=gnu++17
-O3
-DUSER_SETUP_LOADED=1
-DILI9341_DRIVER=1
-DTFT_MOSI=13
-DTFT_SCLK=15
-DTFT_CS=14
-DTFT_DC=12
-DTFT_RST=2
-DLOAD_GLCD=1
-DLOAD_FONT2=1
-DLOAD_FONT4=1
-DLOAD_FONT7=1
-DSPI_FREQUENCY=27000000
-DSPI_READ_FREQUENCY=20000000
-DSPI_TOUCH_FREQUENCY=2500000
-DPINS_RX1=4
-DPINS_TX1=5
-DPINS_RX2=25
-DPINS_TX2=26
-DPINS_GAS=35
-DPINS_BREMS=33
-DFEATURE_3WIRESW
-DPINS_3WIRESW_OUT=0
-DPINS_3WIRESW_IN1=16
-DPINS_3WIRESW_IN2=27
; -DFEATURE_ROTARY
; -DPINS_ROTARY_CLK=16
; -DPINS_ROTARY_DT=27
; -DPINS_ROTARY_SW=0
[env:testbench]
platform = espressif32
board = esp32dev
framework = arduino
board_build.partitions = bobbycar.csv
upload_port = /dev/ttyUSB*
upload_speed = 921600
lib_deps =
TFT_eSPI
https://github.com/Ferdi265/cxx-ring-buffer
lib_compat_mode = strict
build_unflags =
-std=gnu++11
-Os
build_flags =
-std=gnu++17
-O3
-DUSER_SETUP_LOADED=1
-DILI9341_DRIVER=1
-DTFT_MOSI=22
-DTFT_SCLK=21
-DTFT_CS=27
-DTFT_DC=32
-DTFT_RST=25
-DLOAD_GLCD=1
-DLOAD_FONT2=1
-DLOAD_FONT4=1
-DLOAD_FONT7=1
-DSPI_FREQUENCY=27000000
-DSPI_READ_FREQUENCY=20000000
-DSPI_TOUCH_FREQUENCY=2500000
-DPINS_RX1=18
-DPINS_TX1=19
-DPINS_RX2=23
-DPINS_TX2=34
-DPINS_GAS=35
-DPINS_BREMS=33
; -DFEATURE_3WIRESW
; -DPINS_3WIRESW_OUT=17
; -DPINS_3WIRESW_IN1=4
; -DPINS_3WIRESW_IN2=16
; -DFEATURE_ROTARY
; -DPINS_ROTARY_CLK=4
; -DPINS_ROTARY_DT=16
; -DPINS_ROTARY_SW=17

21
src/accessorinterface.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
namespace {
template<typename T>
struct AccessorInterface
{
virtual T getValue() const = 0;
virtual void setValue(T value) = 0;
};
//! A special type of AccessorInterface that allows for simple variable read/write operations
//! Can be used to read and write global settings for example.
template<typename T>
struct RefAccessor : public virtual AccessorInterface<T>
{
virtual T& getRef() const = 0;
T getValue() const override { return getRef(); };
void setValue(T value) override { getRef() = value; };
};
}

11
src/actioninterface.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "utils.h"
namespace {
class ActionInterface
{
public:
virtual void triggered() = 0;
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include "actioninterface.h"
#include "globals.h"
namespace {
class BluetoothBeginAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bluetoothSerial.begin("bobbyquad"))
{
Serial.println("Could not begin bluetooth");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include "actioninterface.h"
#include "globals.h"
namespace {
class BluetoothBeginMasterAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bluetoothSerial.begin("bobbyquad", true))
{
Serial.println("Could not begin bluetooth master");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <HardwareSerial.h>
#include "actioninterface.h"
#include "globals.h"
namespace {
class BluetoothConnectBmsAction : public virtual ActionInterface
{
public:
void triggered() override
{
uint8_t remoteAddress[ESP_BD_ADDR_LEN] = {0xAA, 0xBB, 0xCC, 0xA1, 0x23, 0x45};
if (!bluetoothSerial.connect(remoteAddress))
{
Serial.println("Could not connect bluetooth to bms");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include "actioninterface.h"
#include "globals.h"
namespace {
class BluetoothDisconnectAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bluetoothSerial.disconnect())
{
Serial.println("Could not disconnect bluetooth");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "actioninterface.h"
#include "globals.h"
namespace {
class BluetoothEndAction : public virtual ActionInterface
{
public:
void triggered() override
{
bluetoothSerial.end();
}
};
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "actioninterface.h"
#include "globals.h"
namespace {
class BluetoothFlushAction : public virtual ActionInterface
{
public:
void triggered() override
{
bluetoothSerial.flush();
}
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "actioninterface.h"
#include "bmsutils.h"
namespace {
class BmsTurnOffChargeAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bms::send6Bit(42405, 250, 0))
{
Serial.println("Could not turn off charge mosfet");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "actioninterface.h"
#include "bmsutils.h"
namespace {
class BmsTurnOffDischargeAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bms::send6Bit(42405, 249, 0))
{
Serial.println("Could not turn off discharge mosfet");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "actioninterface.h"
#include "bmsutils.h"
namespace {
class BmsTurnOnChargeAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bms::send6Bit(42405, 250, 1))
{
Serial.println("Could not turn on charge mosfet");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "actioninterface.h"
#include "bmsutils.h"
namespace {
class BmsTurnOnDischargeAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!bms::send6Bit(42405, 249, 1))
{
Serial.println("Could not turn on discharge mosfet");
// TODO: better error handling
}
}
};
}

11
src/actions/dummyaction.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "actioninterface.h"
namespace {
class DummyAction : public virtual ActionInterface
{
public:
void triggered() override {}
};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "actioninterface.h"
#include "utils.h"
namespace {
class LoadSettingsAction : public virtual ActionInterface
{
public:
void triggered() override { loadSettings(); }
};
}

35
src/actions/multiaction.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include "actioninterface.h"
namespace {
template<typename ...T>
class MultiAction;
template<typename T>
class MultiAction<T> : public virtual ActionInterface
{
public:
void triggered() override
{
m_action.triggered();
}
private:
T m_action;
};
template<typename T, typename ...Tmore>
class MultiAction<T, Tmore...> : public virtual MultiAction<Tmore...>
{
public:
void triggered() override
{
m_action.triggered();
MultiAction<Tmore...>::triggered();
}
private:
T m_action;
};
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <Esp.h>
#include "actioninterface.h"
#include "globals.h"
#include "texts.h"
namespace {
class RebootAction : public virtual ActionInterface
{
public:
void triggered() override
{
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_YELLOW);
tft.drawString(TEXT_REBOOT, 5, 5, 4);
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
tft.setTextColor(TFT_WHITE);
tft.drawString("Rebooting now...", 0, 50, 4);
ESP.restart();
}
};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "actioninterface.h"
#include "utils.h"
namespace {
class SaveSettingsAction : public virtual ActionInterface
{
public:
void triggered() override { saveSettings(); }
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "actioninterface.h"
#include "utils.h"
namespace {
template<typename Tscreen, typename ...Targs>
class SwitchScreenAction : public virtual ActionInterface
{
public:
void triggered() override { switchScreen<Tscreen>(std::make_unique<Targs>()...); }
};
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "actioninterface.h"
#include "accessorinterface.h"
namespace {
class ToggleBoolAction : public virtual ActionInterface, public virtual AccessorInterface<bool>
{
public:
void triggered() override
{
setValue(!getValue());
}
};
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "actioninterface.h"
#include "utils.h"
namespace {
class UpdateSwapFrontBackAction : public virtual ActionInterface
{
public:
void triggered() override { updateSwapFrontBack(); }
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include <WiFi.h>
#include "actioninterface.h"
namespace {
class WifiDisconnectAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!WiFi.disconnect())
{
Serial.println("Could not disconnect WiFi");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include <WiFi.h>
#include "actioninterface.h"
namespace {
class WifiEnableIpV6Action : public virtual ActionInterface
{
public:
void triggered() override
{
if (!WiFi.enableIpV6())
{
Serial.println("Could not enableIpV6 WiFi");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include <WiFi.h>
#include "actioninterface.h"
namespace {
class WifiReconnectAction : public virtual ActionInterface
{
public:
void triggered() override
{
if (!WiFi.reconnect())
{
Serial.println("Could not reconnect WiFi");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <HardwareSerial.h>
#include <WiFi.h>
#include "actioninterface.h"
namespace {
class WifiSoftApEnableIpV6Action : public virtual ActionInterface
{
public:
void triggered() override
{
if (!WiFi.softAPenableIpV6())
{
Serial.println("Could not softAPenableIpV6 WiFi");
// TODO: better error handling
}
}
};
}

View File

@ -0,0 +1,37 @@
#pragma once
#include "textinterface.h"
#include "globals.h"
#include "utils.h"
namespace {
template<const char *Ttext, typename TreturnType, TreturnType (BluetoothSerial::*Tmethod)()>
using BluetoothStatusTextHelper = StatusTextHelper<Ttext, BluetoothSerial, &bluetoothSerial, TreturnType, Tmethod>;
constexpr char TEXT_BLUETOOTHAVAILABLE[] = "Available: ";
using BluetoothAvailableText = BluetoothStatusTextHelper<TEXT_BLUETOOTHAVAILABLE, int, &BluetoothSerial::available>;
constexpr char TEXT_BLUETOOTHHASCLIENT[] = "Has client: ";
using BluetoothHasClientText = BluetoothStatusTextHelper<TEXT_BLUETOOTHHASCLIENT, bool, &BluetoothSerial::hasClient>;
//constexpr char TEXT_BLUETOOTHCONNECTED[] = "Connected: ";
//using BluetoothConnectedText = BluetoothStatusTextHelper<TEXT_BLUETOOTHCONNECTED, bool, &BluetoothSerial::connected>;
struct BluetoothConnectedText : public virtual TextInterface {
public:
String text() const override { return String{"connected: "} + toString(bluetoothSerial.connected()); }
};
//constexpr char TEXT_BLUETOOTHISREADY[] = "Is ready: ";
//using BluetoothIsReadyText = BluetoothStatusTextHelper<TEXT_BLUETOOTHISREADY, bool, &BluetoothSerial::isReady>;
struct BluetoothIsReadyText : public virtual TextInterface {
public:
String text() const override { return String{"isReady: "} + toString(bluetoothSerial.isReady()); }
};
//constexpr char TEXT_BLUETOOTHISREADYMASTER[] = "Is ready (M): ";
//using BluetoothIsReadyMasterText = BluetoothStatusTextHelper<TEXT_BLUETOOTHISREADYMASTER, bool, &BluetoothSerial::isReady>;
class BluetoothIsReadyMasterText : public virtual TextInterface {
public:
String text() const override { return String{"isReady (M): "} + toString(bluetoothSerial.isReady(true)); }
};
}

122
src/bmsutils.h Normal file
View File

@ -0,0 +1,122 @@
#pragma once
#include "globals.h"
namespace {
namespace bms {
constexpr auto autoReconnect = false; // causes hangs when not available
bool lastConnected;
unsigned long lastSend;
unsigned long lastReceive;
float voltage;
float current;
float capacity;
int8_t soc;
float cycle;
int16_t power;
float batt[12];
bool send6Bit(int zhen_tou, int address, int data)
{
uint8_t buffer[6];
buffer[0] = (char)((zhen_tou>>8)&255);
buffer[1] = (char)(zhen_tou&255);
buffer[2] = (char)(address&255);
buffer[3] = (char)((data>>8)&255);
buffer[4] = (char)(data&255);
buffer[5] = (char)(buffer[2]+buffer[3]+buffer[4]);
const auto sent = bluetoothSerial.write(buffer, 6);
if (sent != 6)
Serial.printf("send: %lu\r\n", sent);
return sent == 6;
}
void update()
{
const auto now = millis();
if (bluetoothSerial.hasClient() != lastConnected)
{
lastSend = 0;
lastConnected = bluetoothSerial.hasClient();
}
if (bluetoothSerial.hasClient())
{
if (bluetoothSerial.available() >= 140)
{
uint8_t buffer[140];
const auto read = bluetoothSerial.readBytes(buffer, 140);
if (read != 140)
{
Serial.printf("bms read buffer too short %lu\r\n", read);
for (int i = 0; i < read; i++)
Serial.printf("%i ", buffer[i]);
Serial.println();
goto after_read;
}
if (buffer[0] != 170 ||
buffer[1] != 85 ||
buffer[2] != 170 ||
buffer[3] != 255)
{
Serial.println("bms read buffer wrong sequence");
for (const auto &x : buffer)
Serial.printf("%i ", x);
Serial.println();
goto after_read;
}
lastReceive = now;
voltage = static_cast<int16_t>((buffer[4] << 8) | buffer[5]) / 10.f;
current = static_cast<int16_t>((buffer[72] << 8) | buffer[73]) / 10.f;
capacity = static_cast<int32_t>((((((buffer[79] << 8) | buffer[80]) << 8) | buffer[81]) << 8) | buffer[82]) / 1000.f;
soc = buffer[74];
cycle = static_cast<int32_t>((((((buffer[83] << 8) | buffer[84]) << 8) | buffer[85]) << 8) | buffer[86]) / 1000.f;
power = (buffer[113] << 8) | buffer[114];
for (int i = 0; i < 12; i++)
batt[i] = ((buffer[(i*2)+6] * 256) + buffer[(i*2)+7]) / 1000.f;
}
// else if (bluetoothSerial.available())
// {
// Serial.printf("available() = %i\r\n", bluetoothSerial.available());
// while (bluetoothSerial.available())
// Serial.printf("%i ", bluetoothSerial.read());
// Serial.println();
// }
after_read:
if (!lastSend || now-lastSend >= 1000)
{
Serial.println("requresting bms live values");
if (!send6Bit(56283, 0, 0))
Serial.println("could not request bms live values");
lastSend = now;
}
}
else if (autoReconnect)
{
if (!lastSend || now-lastSend >= 500)
{
uint8_t remoteAddress[ESP_BD_ADDR_LEN] = {0xAA, 0xBB, 0xCC, 0xA1, 0x23, 0x45};
Serial.println("connect()");
const auto result = bluetoothSerial.connect(remoteAddress);
Serial.printf("connect() returned %s\r\n", result?"true":"false");
lastSend = now;
}
}
}
}
}

View File

@ -0,0 +1,122 @@
#pragma once
#include <stdint.h>
namespace {
enum class ControlType : uint8_t {
Commutation,
Sinusoidal,
FieldOrientedControl
};
enum class ControlMode : uint8_t {
OpenMode,
Voltage,
Speed, // Only with FieldOrientedControl
Torque // Only with FieldOrientedControl
};
struct MotorState {
bool enable = false;
int16_t pwm = 0;
ControlType ctrlTyp = ControlType::FieldOrientedControl;
ControlMode ctrlMod = ControlMode::OpenMode;
int16_t iMotMax = 15; // [A] Maximum motor current limit
int16_t iDcMax = 17; // [A] Maximum DC Link current limit (This is the final current protection. Above this value, current chopping is applied. To avoid this make sure that I_DC_MAX = I_MOT_MAX + 2A)
int16_t nMotMax = 1000; // [rpm] Maximum motor speed limit
int16_t fieldWeakMax = 10; // [A] Maximum Field Weakening D axis current (only for FOC). Higher current results in higher maximum speed.
int16_t phaseAdvMax = 40; // [deg] Maximum Phase Advance angle (only for SIN). Higher angle results in higher maximum speed.
};
uint16_t calculateChecksum(MotorState state) {
return
uint16_t(state.enable) ^
state.pwm ^
uint16_t(state.ctrlTyp) ^
uint16_t(state.ctrlMod) ^
state.iMotMax ^
state.iDcMax ^
state.nMotMax ^
state.fieldWeakMax ^
state.phaseAdvMax;
}
struct BuzzerState {
uint8_t freq = 0;
uint8_t pattern = 0;
};
uint16_t calculateChecksum(BuzzerState state) {
return state.freq ^ state.pattern;
}
struct Command {
static constexpr uint16_t VALID_HEADER = 0xAAAA;
static constexpr uint16_t INVALID_HEADER = 0xFFFF;
uint16_t start;
MotorState left, right;
BuzzerState buzzer;
bool poweroff = false;
bool led = false;
uint16_t checksum;
};
uint16_t calculateChecksum(Command command) {
return command.start ^
calculateChecksum(command.left) ^
calculateChecksum(command.right) ^
calculateChecksum(command.buzzer) ^
command.poweroff ^
command.led;
}
struct MotorFeedback {
int16_t angle = 0;
int16_t speed = 0;
uint8_t error = 0;
int16_t current = 0;
uint32_t chops = 0;
bool hallA = false,
hallB = false,
hallC = false;
};
uint16_t calculateChecksum(MotorFeedback feedback) {
return feedback.angle ^ feedback.speed ^
feedback.error ^ feedback.current ^
feedback.chops ^
feedback.hallA ^ feedback.hallB ^ feedback.hallC;
}
struct Feedback {
static constexpr uint16_t VALID_HEADER = 0xAAAA;
static constexpr uint16_t INVALID_HEADER = 0xFFFF;
uint16_t start;
MotorFeedback left, right;
int16_t batVoltage = 0;
int16_t boardTemp = 0;
int16_t timeoutCntSerial = 0;
uint16_t checksum;
};
uint16_t calculateChecksum(Feedback feedback) {
return feedback.start ^
calculateChecksum(feedback.left) ^
calculateChecksum(feedback.right) ^
feedback.batVoltage ^
feedback.boardTemp ^
feedback.timeoutCntSerial;
}
}

150
src/changevaluedisplay.h Normal file
View File

@ -0,0 +1,150 @@
#pragma once
#include "display.h"
#include "textinterface.h"
#include "actioninterface.h"
#include "accessorinterface.h"
#include "widgets/label.h"
#include "globals.h"
#include "utils.h"
namespace {
class ChangeValueDisplayInterface : public Display, public virtual TextInterface, public virtual ActionInterface
{
public:
void initScreen() override;
ChangeValueDisplayInterface *asChangeValueDisplayInterface() override { return this; }
const ChangeValueDisplayInterface *asChangeValueDisplayInterface() const override { return this; }
virtual int shownValue() const = 0;
virtual void setShownValue(int value) = 0;
virtual void confirm() = 0;
protected:
Label m_titleLabel{5, 5}; // 230, 25
Label m_valueLabel{26, 81}; // 188, 53
};
template<typename Tvalue>
class ChangeValueDisplaySettingsInterface
{
public:
virtual Tvalue step() const { return 1; };
};
template<typename Tvalue, typename Tratio>
class RatioNumberStep : public virtual ChangeValueDisplaySettingsInterface<Tvalue>
{
public:
Tvalue step() const override { return Tvalue(Tratio::num) / Tratio::den; }
};
template<typename Tvalue>
class ChangeValueDisplay : public ChangeValueDisplayInterface, public virtual AccessorInterface<Tvalue>, public virtual ChangeValueDisplaySettingsInterface<Tvalue>
{
using Base = ChangeValueDisplayInterface;
public:
void start() override;
void update() override;
void redraw() override;
void rotate(int offset) override;
void button() override;
int shownValue() const { return m_value; }
void setShownValue(int value) { m_value = value; }
void confirm() override;
private:
Tvalue m_value{};
int m_rotateOffset;
bool m_pressed{};
};
void ChangeValueDisplayInterface::initScreen()
{
tft.fillScreen(TFT_BLACK);
m_titleLabel.start();
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
tft.drawRect(25, 75, 190, 65, TFT_WHITE);
m_valueLabel.start();
tft.setTextFont(4);
tft.setTextColor(TFT_WHITE);
tft.drawString("Change value and", 10, 160);
tft.drawString("press button to", 10, 185);
tft.drawString("confirm and go", 10, 210);
tft.drawString("back.", 10, 235);
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::start()
{
m_value = static_cast<AccessorInterface<Tvalue>*>(this)->getValue();
m_rotateOffset = 0;
m_pressed = false;
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::update()
{
if (!m_pressed)
{
const auto rotateOffset = m_rotateOffset;
m_rotateOffset = 0;
m_value -= rotateOffset * static_cast<ChangeValueDisplaySettingsInterface<Tvalue>*>(this)->step();
}
else
{
static_cast<AccessorInterface<Tvalue>*>(this)->setValue(m_value);
triggered();
}
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::redraw()
{
tft.setTextFont(4);
tft.setTextColor(TFT_YELLOW);
m_titleLabel.redraw(text());
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextFont(7);
m_valueLabel.redraw(String{m_value});
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::rotate(int offset)
{
m_rotateOffset += offset;
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::button()
{
m_pressed = true;
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::confirm()
{
m_pressed = true;
}
}
#include "changevaluedisplay_bool.h"
#include "changevaluedisplay_controlmode.h"
#include "changevaluedisplay_controltype.h"
#include "changevaluedisplay_larsmmode_mode.h"
#include "changevaluedisplay_wifi_mode_t.h"
#include "changevaluedisplay_wifi_power_t.h"

View File

@ -0,0 +1,52 @@
#pragma once
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "actioninterface.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
template<>
class ChangeValueDisplay<bool> :
public MenuDisplay,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_TRUE>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_FALSE>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, DummyAction, StaticMenuItemIcon<&icons::back>>
>,
public virtual AccessorInterface<bool>,
public virtual ActionInterface
{
using Base = MenuDisplay;
public:
void start() override;
void itemPressed(int index) override;
};
void ChangeValueDisplay<bool>::start()
{
Base::start();
if (getValue() == true)
setSelectedIndex(0);
else if (getValue() == false)
setSelectedIndex(1);
}
void ChangeValueDisplay<bool>::itemPressed(int index)
{
switch (index)
{
case 0: setValue(true); break;
case 1: setValue(false); break;
}
triggered();
}
}

View File

@ -0,0 +1,64 @@
#pragma once
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
template<>
class ChangeValueDisplay<ControlMode> :
public MenuDisplay,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_OPENMODE>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_VOLTAGE>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_SPEED>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_TORQUE>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, DummyAction, StaticMenuItemIcon<&icons::back>>
>,
public virtual AccessorInterface<ControlMode>,
public virtual ActionInterface
{
using Base = MenuDisplay;
public:
void start() override;
void itemPressed(int index) override;
};
void ChangeValueDisplay<ControlMode>::start()
{
Base::start();
if (getValue() == ControlMode::OpenMode)
setSelectedIndex(0);
else if (getValue() == ControlMode::Voltage)
setSelectedIndex(1);
else if (getValue() == ControlMode::Speed)
setSelectedIndex(2);
else if (getValue() == ControlMode::Torque)
setSelectedIndex(3);
else
{
Serial.printf("Unknown ControlMode: %i", int(getValue()));
setSelectedIndex(4);
}
}
void ChangeValueDisplay<ControlMode>::itemPressed(int index)
{
switch (index)
{
case 0: setValue(ControlMode::OpenMode); break;
case 1: setValue(ControlMode::Voltage); break;
case 2: setValue(ControlMode::Speed); break;
case 3: setValue(ControlMode::Torque); break;
}
triggered();
}
}

View File

@ -0,0 +1,60 @@
#pragma once
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
template<>
class ChangeValueDisplay<ControlType> :
public MenuDisplay,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_COMMUTATION>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_SINUSOIDAL>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_FIELDORIENTEDCONTROL>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, DummyAction, StaticMenuItemIcon<&icons::back>>
>,
public virtual AccessorInterface<ControlType>,
public virtual ActionInterface
{
using Base = MenuDisplay;
public:
void start() override;
void itemPressed(int index) override;
};
void ChangeValueDisplay<ControlType>::start()
{
Base::start();
if (getValue() == ControlType::Commutation)
setSelectedIndex(0);
else if (getValue() == ControlType::Sinusoidal)
setSelectedIndex(1);
else if (getValue() == ControlType::FieldOrientedControl)
setSelectedIndex(2);
else
{
Serial.printf("Unknown ControlType: %i", int(getValue()));
setSelectedIndex(3);
}
}
void ChangeValueDisplay<ControlType>::itemPressed(int index)
{
switch (index)
{
case 0: setValue(ControlType::Commutation); break;
case 1: setValue(ControlType::Sinusoidal); break;
case 2: setValue(ControlType::FieldOrientedControl); break;
}
triggered();
}
}

View File

@ -0,0 +1,65 @@
#pragma once
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
#include "modes/larsmmode.h"
namespace {
template<>
class ChangeValueDisplay<LarsmModeMode> :
public MenuDisplay,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_LARSMMODE1>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_LARSMMODE2>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_LARSMMODE3>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_LARSMMODE4>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, DummyAction, StaticMenuItemIcon<&icons::back>>
>,
public virtual AccessorInterface<LarsmModeMode>,
public virtual ActionInterface
{
using Base = MenuDisplay;
public:
void start() override;
void itemPressed(int index) override;
};
void ChangeValueDisplay<LarsmModeMode>::start()
{
Base::start();
if (getValue() == LarsmModeMode::Mode1)
setSelectedIndex(0);
else if (getValue() == LarsmModeMode::Mode2)
setSelectedIndex(1);
else if (getValue() == LarsmModeMode::Mode3)
setSelectedIndex(2);
else if (getValue() == LarsmModeMode::Mode4)
setSelectedIndex(3);
else
{
Serial.printf("Unknown LarsmModeMode: %i", int(getValue()));
setSelectedIndex(4);
}
}
void ChangeValueDisplay<LarsmModeMode>::itemPressed(int index)
{
switch (index)
{
case 0: setValue(LarsmModeMode::Mode1); break;
case 1: setValue(LarsmModeMode::Mode2); break;
case 2: setValue(LarsmModeMode::Mode3); break;
case 3: setValue(LarsmModeMode::Mode4); break;
}
triggered();
}
}

View File

@ -0,0 +1,66 @@
#pragma once
#include <esp_wifi_types.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
template<>
class ChangeValueDisplay<wifi_mode_t> :
public MenuDisplay,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_WIFI_MODE_NULL>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_MODE_STA>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_MODE_AP>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_MODE_APSTA>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, DummyAction, StaticMenuItemIcon<&icons::back>>
>,
public virtual AccessorInterface<wifi_mode_t>,
public virtual ActionInterface
{
using Base = MenuDisplay;
public:
void start() override;
void itemPressed(int index) override;
};
void ChangeValueDisplay<wifi_mode_t>::start()
{
Base::start();
if (getValue() == WIFI_MODE_NULL)
setSelectedIndex(0);
else if (getValue() == WIFI_MODE_STA)
setSelectedIndex(1);
else if (getValue() == WIFI_MODE_AP)
setSelectedIndex(2);
else if (getValue() == WIFI_MODE_APSTA)
setSelectedIndex(3);
else
{
Serial.printf("Unknown wifi_mode_t: %i", int(getValue()));
setSelectedIndex(4);
}
}
void ChangeValueDisplay<wifi_mode_t>::itemPressed(int index)
{
switch (index)
{
case 0: setValue(WIFI_MODE_NULL); break;
case 1: setValue(WIFI_MODE_STA); break;
case 2: setValue(WIFI_MODE_AP); break;
case 3: setValue(WIFI_MODE_APSTA); break;
}
triggered();
}
}

View File

@ -0,0 +1,98 @@
#pragma once
#include <WiFiGeneric.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
template<>
class ChangeValueDisplay<wifi_power_t> :
public MenuDisplay,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_19_5dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_19dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_18_5dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_17dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_15dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_13dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_11dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_8_5dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_7dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_5dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_2dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFI_POWER_MINUS_1dBm>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, DummyAction, StaticMenuItemIcon<&icons::back>>
>,
public virtual AccessorInterface<wifi_power_t>,
public virtual ActionInterface
{
using Base = MenuDisplay;
public:
void start() override;
void itemPressed(int index) override;
};
void ChangeValueDisplay<wifi_power_t>::start()
{
Base::start();
if (getValue() == WIFI_POWER_19_5dBm)
setSelectedIndex(0);
else if (getValue() == WIFI_POWER_19dBm)
setSelectedIndex(1);
else if (getValue() == WIFI_POWER_18_5dBm)
setSelectedIndex(2);
else if (getValue() == WIFI_POWER_17dBm)
setSelectedIndex(3);
else if (getValue() == WIFI_POWER_15dBm)
setSelectedIndex(4);
else if (getValue() == WIFI_POWER_13dBm)
setSelectedIndex(5);
else if (getValue() == WIFI_POWER_11dBm)
setSelectedIndex(6);
else if (getValue() == WIFI_POWER_8_5dBm)
setSelectedIndex(7);
else if (getValue() == WIFI_POWER_7dBm)
setSelectedIndex(8);
else if (getValue() == WIFI_POWER_5dBm)
setSelectedIndex(9);
else if (getValue() == WIFI_POWER_2dBm)
setSelectedIndex(10);
else if (getValue() == WIFI_POWER_MINUS_1dBm)
setSelectedIndex(11);
else
{
Serial.printf("Unknown wifi_power_t: %i", int(getValue()));
setSelectedIndex(12);
}
}
void ChangeValueDisplay<wifi_power_t>::itemPressed(int index)
{
switch (index)
{
case 0: setValue(WIFI_POWER_19_5dBm); break;
case 1: setValue(WIFI_POWER_19dBm); break;
case 2: setValue(WIFI_POWER_18_5dBm); break;
case 3: setValue(WIFI_POWER_17dBm); break;
case 4: setValue(WIFI_POWER_15dBm); break;
case 5: setValue(WIFI_POWER_13dBm); break;
case 6: setValue(WIFI_POWER_11dBm); break;
case 7: setValue(WIFI_POWER_8_5dBm); break;
case 8: setValue(WIFI_POWER_7dBm); break;
case 9: setValue(WIFI_POWER_5dBm); break;
case 10: setValue(WIFI_POWER_2dBm); break;
case 11: setValue(WIFI_POWER_MINUS_1dBm); break;
}
triggered();
}
}

17
src/checkboxicon.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "menuitem.h"
#include "accessorinterface.h"
#include "icons/checked.h"
#include "icons/unchecked.h"
namespace {
class CheckboxIcon : public virtual MenuItemIconInterface, public virtual AccessorInterface<bool>
{
public:
const MenuItemIcon *icon() const override
{
return getValue() ? &icons::checked : &icons::unchecked;
}
};
}

32
src/colorinterface.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "TFT_eSPI.h"
namespace {
class ColorInterface {
public:
virtual int color() const { return TFT_WHITE; };
};
template<int TColor>
class StaticColor : public virtual ColorInterface
{
public:
static constexpr int STATIC_COLOR = TColor;
int color() const override { return TColor; }
};
using DefaultColor = StaticColor<TFT_WHITE>;
using DisabledColor = StaticColor<TFT_DARKGREY>;
class ChangeableColor : public virtual ColorInterface
{
public:
int color() const override { return m_color; }
void setColor(const int &color) { m_color = color; }
private:
int m_color;
};
}

28
src/controller.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <functional>
#include "bobbycar-protocol/protocol.h"
#include "feedbackparser.h"
class HardwareSerial;
namespace {
struct Controller {
Controller(HardwareSerial &serial, bool &enableLeft, bool &enableRight, bool &invertLeft, bool &invertRight) :
serial{serial}, enableLeft{enableLeft}, enableRight{enableRight}, invertLeft{invertLeft}, invertRight{invertRight}
{
}
std::reference_wrapper<HardwareSerial> serial;
bool &enableLeft, &enableRight, &invertLeft, &invertRight;
Command command{};
bool feedbackValid{};
Feedback feedback{};
FeedbackParser parser{serial, feedbackValid, feedback};
};
}

15
src/debugcolorhelpers.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "colorinterface.h"
#include "globals.h"
namespace {
template<Controller &Tcontroller, int TsuccessColor>
class FeedbackColor : public virtual ColorInterface { public: int color() const { return Tcontroller.feedbackValid ? TsuccessColor : TFT_RED; } };
template<int TsuccessColor>
using FrontFeedbackColor = FeedbackColor<front, TsuccessColor>;
template<int TsuccessColor>
using BackFeedbackColor = FeedbackColor<back, TsuccessColor>;
}

90
src/debugtexthelpers.h Normal file
View File

@ -0,0 +1,90 @@
#pragma once
#include "textinterface.h"
#include "globals.h"
#include "utils.h"
namespace {
template<Controller &controller>
struct ControllerTexts
{
ControllerTexts() = delete;
~ControllerTexts() = delete;
struct BuzzerFreqText : public virtual TextInterface { public: String text() const override { return String{"buzzerFreq: "} + toString(controller.command.buzzer.freq); } };
struct BuzzerPatternText : public virtual TextInterface { public: String text() const override { return String{"buzzerPattern: "} + toString(controller.command.buzzer.pattern); } };
struct PoweroffText : public virtual TextInterface { public: String text() const override { return String{"poweroff: "} + toString(controller.command.poweroff); } };
struct LedText : public virtual TextInterface { public: String text() const override { return String{"led: "} + toString(controller.command.led); } };
struct LeftCommand
{
LeftCommand() = delete;
~LeftCommand() = delete;
struct EnableText : public virtual TextInterface { public: String text() const override { return String{"enable: "} + toString(controller.command.left.enable); } };
struct PwmText : public virtual TextInterface { public: String text() const override { return String{"pwm: "} + toString(controller.command.left.pwm); } };
struct CtrlTypText : public virtual TextInterface { public: String text() const override { return String{"ctrlTyp: "} + toString(controller.command.left.ctrlTyp); } };
struct CtrlModText : public virtual TextInterface { public: String text() const override { return String{"ctrlMod: "} + toString(controller.command.left.ctrlMod); } };
struct IMotMaxText : public virtual TextInterface { public: String text() const override { return String{"iMotMax: "} + toString(controller.command.left.iMotMax); } };
struct IDcMaxText : public virtual TextInterface { public: String text() const override { return String{"iDcMax: "} + toString(controller.command.left.iDcMax); } };
struct NMotMaxText : public virtual TextInterface { public: String text() const override { return String{"nMotMax: "} + toString(controller.command.left.nMotMax); } };
struct FieldWeakMaxText : public virtual TextInterface { public: String text() const override { return String{"fieldWeakMax: "} + toString(controller.command.left.fieldWeakMax); } };
struct PhaseAdvMaxText : public virtual TextInterface { public: String text() const override { return String{"phaseAdvMax: "} + toString(controller.command.left.phaseAdvMax); } };
};
struct RightCommand
{
RightCommand() = delete;
~RightCommand() = delete;
struct EnableText : public virtual TextInterface { public: String text() const override { return String{"enable: "} + toString(controller.command.right.enable); } };
struct PwmText : public virtual TextInterface { public: String text() const override { return String{"pwm: "} + toString(controller.command.right.pwm); } };
struct CtrlTypText : public virtual TextInterface { public: String text() const override { return String{"ctrlTyp: "} + toString(controller.command.right.ctrlTyp); } };
struct CtrlModText : public virtual TextInterface { public: String text() const override { return String{"ctrlMod: "} + toString(controller.command.right.ctrlMod); } };
struct IMotMaxText : public virtual TextInterface { public: String text() const override { return String{"iMotMax: "} + toString(controller.command.right.iMotMax); } };
struct IDcMaxText : public virtual TextInterface { public: String text() const override { return String{"iDcMax: "} + toString(controller.command.right.iDcMax); } };
struct NMotMaxText : public virtual TextInterface { public: String text() const override { return String{"nMotMax: "} + toString(controller.command.right.nMotMax); } };
struct FieldWeakMaxText : public virtual TextInterface { public: String text() const override { return String{"fieldWeakMax: "} + toString(controller.command.right.fieldWeakMax); } };
struct PhaseAdvMaxText : public virtual TextInterface { public: String text() const override { return String{"phaseAdvMax: "} + toString(controller.command.right.phaseAdvMax); } };
};
struct BatVoltageText : public virtual TextInterface { public: String text() const override { auto line = String{"batVoltage: "}; if (controller.feedbackValid) line += toString(controller.feedback.batVoltage); return line; } };
struct BatVoltageFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"batVoltage: "}; if (controller.feedbackValid) line += toString(fixBatVoltage(controller.feedback.batVoltage)) + 'V'; return line; } };
struct BoardTempText : public virtual TextInterface { public: String text() const override { auto line = String{"boardTemp: "}; if (controller.feedbackValid) line += toString(controller.feedback.boardTemp); return line; } };
struct BoardTempFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"boardTemp: "}; if (controller.feedbackValid) line += toString(fixBoardTemp(controller.feedback.boardTemp)) + 'C'; return line; } };
struct TimeoutCntSerialText : public virtual TextInterface { public: String text() const override { auto line = String{"timeoutCntSerial: "}; if (controller.feedbackValid) line += toString(controller.feedback.timeoutCntSerial); return line; } };
struct LeftFeedback
{
LeftFeedback() = delete;
~LeftFeedback() = delete;
struct AngleText : public virtual TextInterface { public: String text() const override { auto line = String{"angle: "}; if (controller.feedbackValid) line += toString(controller.feedback.left.angle); return line; } };
struct SpeedText : public virtual TextInterface { public: String text() const override { auto line = String{"speed: "}; if (controller.feedbackValid) line += toString(controller.feedback.left.speed); return line; } };
struct SpeedKmhText : public virtual TextInterface { public: String text() const override { auto line = String{"speed kmh: "}; if (controller.feedbackValid) line += toString(convertToKmh(controller.feedback.left.speed)); return line; } };
struct ErrorText : public virtual TextInterface { public: String text() const override { auto line = String{"error: "}; if (controller.feedbackValid) line += toString(controller.feedback.left.error); return line; } };
struct CurrentText : public virtual TextInterface { public: String text() const override { auto line = String{"current: "}; if (controller.feedbackValid) line += toString(controller.feedback.left.current); return line; } };
struct CurrentFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"current: "}; if (controller.feedbackValid) line += toString(fixCurrent(controller.feedback.left.current)) + 'A'; return line; } };
struct ChopsText : public virtual TextInterface { public: String text() const override { auto line = String{"chops: "}; if (controller.feedbackValid) line += toString(controller.feedback.left.chops); return line; } };
struct HallText : public virtual TextInterface { public: String text() const override { auto line = String{"hall: "}; if (controller.feedbackValid) line += hallString(controller.feedback.left); return line; } };
};
struct RightFeedback
{
RightFeedback() = delete;
~RightFeedback() = delete;
struct AngleText : public virtual TextInterface { public: String text() const override { auto line = String{"angle: "}; if (controller.feedbackValid) line += toString(controller.feedback.right.angle); return line; } };
struct SpeedText : public virtual TextInterface { public: String text() const override { auto line = String{"speed: "}; if (controller.feedbackValid) line += toString(controller.feedback.right.speed); return line; } };
struct SpeedKmhText : public virtual TextInterface { public: String text() const override { auto line = String{"speed kmh: "}; if (controller.feedbackValid) line += toString(convertToKmh(controller.feedback.right.speed)); return line; } };
struct ErrorText : public virtual TextInterface { public: String text() const override { auto line = String{"error: "}; if (controller.feedbackValid) line += toString(controller.feedback.right.error); return line; } };
struct CurrentText : public virtual TextInterface { public: String text() const override { auto line = String{"current: "}; if (controller.feedbackValid) line += toString(controller.feedback.right.current); return line; } };
struct CurrentFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"current: "}; if (controller.feedbackValid) line += toString(fixCurrent(controller.feedback.right.current)) + 'A'; return line; } };
struct ChopsText : public virtual TextInterface { public: String text() const override { auto line = String{"chops: "}; if (controller.feedbackValid) line += toString(controller.feedback.right.chops); return line; } };
struct HallText : public virtual TextInterface { public: String text() const override { auto line = String{"hall: "}; if (controller.feedbackValid) line += hallString(controller.feedback.right); return line; } };
};
};
using FrontTexts = ControllerTexts<front>;
using BackTexts = ControllerTexts<back>;
}

17
src/demodisplay.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "actioninterface.h"
#include "display.h"
namespace {
class DemoDisplay : public Display, public virtual ActionInterface
{
public:
void button() override;
};
void DemoDisplay::button()
{
triggered();
}
}

30
src/display.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include <WString.h>
namespace {
class MenuDisplay;
class ChangeValueDisplayInterface;
}
namespace {
class Display {
public:
virtual ~Display() = default;
virtual void start() {};
virtual void initScreen() {};
virtual void update() {};
virtual void redraw() {};
virtual void stop() {}
virtual void rotate(int offset) {}
virtual void button() {}
virtual MenuDisplay *asMenuDisplay() { return nullptr; }
virtual const MenuDisplay *asMenuDisplay() const { return nullptr; }
virtual ChangeValueDisplayInterface *asChangeValueDisplayInterface() { return nullptr; }
virtual const ChangeValueDisplayInterface *asChangeValueDisplayInterface() const { return nullptr; }
};
}

89
src/displays/bmsdisplay.h Normal file
View File

@ -0,0 +1,89 @@
#pragma once
#include <Arduino.h>
#include "demodisplay.h"
#include "actions/switchscreenaction.h"
#include "globals.h"
#include "bmsutils.h"
#include "widgets/label.h"
namespace {
class MainMenu;
class MetersDisplay;
class StatusDisplay;
}
namespace {
class BmsDisplay : public DemoDisplay, public SwitchScreenAction<MainMenu>
{
public:
void initScreen() override;
void redraw() override;
void rotate(int offset) override;
Label m_statusLabel{0, 0};
Label m_voltageLabel{105, 50};
Label m_currentLabel{105, 75};
Label m_capacityLabel{105, 100};
Label m_socLabel{105, 125};
Label m_cycleLabel{105, 150};
Label m_powerLabel{105, 175};
std::array<Label, 12> m_battLabels{{
Label{0, 225}, Label{60, 225}, Label{120, 225}, Label{180, 225},
Label{0, 250}, Label{60, 250}, Label{120, 250}, Label{180, 250},
Label{0, 275}, Label{60, 275}, Label{120, 275}, Label{180, 275}
}};
};
void BmsDisplay::initScreen()
{
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextFont(2);
m_statusLabel.start();
m_statusLabel.redraw("init");
tft.setTextFont(4);
tft.drawString("Voltage:", 0, 50);
m_voltageLabel.start();
tft.drawString("Current:", 0, 75);
m_currentLabel.start();
tft.drawString("Capacity:", 0, 100);
m_capacityLabel.start();
tft.drawString("SOC:", 0, 125);
m_socLabel.start();
tft.drawString("Cycle:", 0, 150);
m_cycleLabel.start();
tft.drawString("Power:", 0, 175);
m_powerLabel.start();
for (auto &label : m_battLabels)
label.start();
}
void BmsDisplay::redraw()
{
m_statusLabel.redraw(bluetoothSerial.hasClient() ? "connected" : "not connected");
m_voltageLabel.redraw(String{bms::voltage} + 'V');
m_currentLabel.redraw(String{bms::current} + 'A');
m_capacityLabel.redraw(String{int(bms::capacity)} + "mAh");
m_socLabel.redraw(String{bms::soc} + '%');
m_cycleLabel.redraw(String{bms::cycle} + "AH");
m_powerLabel.redraw(String{bms::power} + 'W');
for (int i = 0; i < 12; i++)
m_battLabels[i].redraw(String{bms::batt[i]});
}
void BmsDisplay::rotate(int offset)
{
if (offset < 0)
switchScreen<MetersDisplay>();
else if (offset > 0)
switchScreen<StatusDisplay>();
}
}

View File

@ -0,0 +1,107 @@
#pragma once
#include <array>
#include <WString.h>
#include "demodisplay.h"
#include "actions/switchscreenaction.h"
#include "globals.h"
#include "texts.h"
#include "widgets/label.h"
#include "widgets/progressbar.h"
#include "modes/ignoreinputmode.h"
namespace {
class StatusDisplay;
class PotiSettingsMenu;
}
namespace {
class CalibrateDisplay : public DemoDisplay
{
using Base = DemoDisplay;
public:
CalibrateDisplay() = default;
CalibrateDisplay(bool bootup);
void start() override;
void initScreen() override;
void redraw() override;
void stop() override;
void triggered() override;
private:
const bool m_bootup{false};
ModeInterface *m_oldMode;
IgnoreInputMode m_mode{0, ControlType::FieldOrientedControl, ControlMode::Torque};
std::array<Label, 4> m_labels {{
Label{25, 50}, // 100, 23
Label{25, 75}, // 100, 23
Label{25, 100}, // 100, 23
Label{25, 125} // 100, 23
}};
ProgressBar m_progressBar0{20, 200, 200, 10, 0, 1000};
ProgressBar m_progressBar1{20, 230, 200, 10, 0, 1000};
};
CalibrateDisplay::CalibrateDisplay(bool bootup) :
m_bootup{bootup}
{
}
void CalibrateDisplay::start()
{
m_oldMode = currentMode;
currentMode = &m_mode;
}
void CalibrateDisplay::initScreen()
{
tft.fillScreen(TFT_BLACK);
tft.setTextFont(4);
tft.setTextColor(TFT_YELLOW);
tft.drawString(TEXT_CALIBRATE, 5, 5, 4);
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
for (auto &label : m_labels)
label.start();
m_progressBar0.start();
m_progressBar1.start();
}
void CalibrateDisplay::redraw()
{
m_labels[0].redraw(String{gas});
m_labels[1].redraw(String{raw_gas});
m_labels[2].redraw(String{brems});
m_labels[3].redraw(String{raw_brems});
m_progressBar0.redraw(gas);
m_progressBar1.redraw(brems);
}
void CalibrateDisplay::stop()
{
if (currentMode == &m_mode)
currentMode = m_oldMode;
}
void CalibrateDisplay::triggered()
{
if (m_bootup)
switchScreen<StatusDisplay>();
else
switchScreen<PotiSettingsMenu>();
}
}

View File

@ -0,0 +1,51 @@
#pragma once
#include "demodisplay.h"
#include "actions/switchscreenaction.h"
#include "textinterface.h"
#include "widgets/label.h"
#include "widgets/graph.h"
#include "globals.h"
#include "statistics.h"
namespace {
class GraphsMenu;
}
namespace {
class DualGraphDisplay : public DemoDisplay, public SwitchScreenAction<GraphsMenu>
{
using Base = DemoDisplay;
public:
void initScreen() override;
void redraw() override;
private:
Label m_titleLabel{5, 5}; // 230, 25
Graph<200, 1> m_graph0{0, 40, 133};
Graph<200, 1> m_graph1{0, 179, 133};
};
void DualGraphDisplay::initScreen()
{
tft.fillScreen(TFT_BLACK);
m_titleLabel.start();
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
m_graph0.start({statistics::gas});
m_graph1.start({statistics::brems});
}
void DualGraphDisplay::redraw()
{
tft.setTextFont(4);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
m_titleLabel.redraw("Gas/Brems dual");
m_graph0.redraw({statistics::gas});
m_graph1.redraw({statistics::brems});
}
}

View File

@ -0,0 +1,188 @@
#pragma once
#include <bitset>
#include <memory>
#include <Arduino.h>
#include <HardwareSerial.h>
#include "demodisplay.h"
#include "actions/switchscreenaction.h"
namespace {
class DemosMenu;
}
namespace {
class GameOfLifeDisplay : public DemoDisplay, public SwitchScreenAction<DemosMenu>
{
using Base = DemoDisplay;
public:
void start() override;
void initScreen() override;
void redraw() override;
void stop() override;
private:
//Draws the grid on the display
void drawGrid();
//Initialise Grid
void initGrid();
// Check the Moore neighborhood
int getNumberOfNeighbors(int x, int y);
//Compute the CA. Basically everything related to CA starts here
void computeCA();
//static const constexpr auto GRIDX = 80;
//static const constexpr auto GRIDY = 60;
//static const constexpr auto CELLXY = 4;
static const constexpr auto GRIDX = 160;
static const constexpr auto GRIDY = 120;
static const constexpr auto CELLXY = 2;
static const constexpr auto GEN_DELAY = 0;
template<typename T> auto index(T x, T y)
{
if (x >= GRIDX)
{
Serial.printf("x: %i", x);
return 0;
}
if (y >= GRIDY)
{
Serial.printf("y: %i", x);
return 0;
}
return (x * GRIDX) + y;
}
struct Data
{
std::bitset<GRIDX*GRIDY> grid, newgrid;
};
std::unique_ptr<Data> m_data;
int gen = 0;
};
void GameOfLifeDisplay::start()
{
m_data = std::make_unique<Data>();
}
void GameOfLifeDisplay::initScreen()
{
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
}
void GameOfLifeDisplay::redraw()
{
if (gen == 0)
{
tft.fillScreen(TFT_BLACK);
initGrid();
}
computeCA();
drawGrid();
m_data->grid = m_data->newgrid;
// for (int16_t x = 1; x < GRIDX-1; x++) {
// for (int16_t y = 1; y < GRIDY-1; y++) {
// grid[index(x,y)] = m_data->newgrid[index(x,y)];
// }
// }
if (++gen == 200)
gen = 0;
}
void GameOfLifeDisplay::stop()
{
tft.setRotation(0);
m_data = 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_data->grid[index(x,y)]) != (m_data->newgrid[index(x,y)])) {
if (m_data->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_data->newgrid[index(x,y)] = 0;
if (x == 0 || x == GRIDX - 1 || y == 0 || y == GRIDY - 1)
m_data->grid[index(x,y)] = 0;
else
{
if (random(3) == 1)
m_data->grid[index(x,y)] = 1;
else
m_data->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_data->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_data->grid[index(x,y)] == true && (neighbors == 2 || neighbors == 3 ))
m_data->newgrid[index(x,y)] = true;
else if (m_data->grid[index(x,y)] == 1)
m_data->newgrid[index(x,y)] = false;
if (m_data->grid[index(x,y)] == false && (neighbors == 3))
m_data->newgrid[index(x,y)] = true;
else if (m_data->grid[index(x,y)] == 0)
m_data->newgrid[index(x,y)] = false;
}
}
}
}

View File

@ -0,0 +1,70 @@
#pragma once
#include "demodisplay.h"
#include "actions/switchscreenaction.h"
#include "textinterface.h"
#include "widgets/label.h"
#include "widgets/graph.h"
#include "globals.h"
#include "statistics.h"
namespace {
class GraphsMenu;
}
namespace {
template<size_t COUNT>
class MultiStatisticsInterface
{
public:
virtual std::array<std::reference_wrapper<const statistics::ContainerType>, COUNT> getBuffers() const = 0;
};
class MultiStatisticsSingleImpl : public virtual MultiStatisticsInterface<1>, public virtual BufferAccessorInterface
{
public:
std::array<std::reference_wrapper<const statistics::ContainerType>, 1> getBuffers() const
{
return {getBuffer()};
}
};
template<size_t COUNT>
class GraphDisplay : public DemoDisplay, public SwitchScreenAction<GraphsMenu>, public virtual TextInterface, public virtual MultiStatisticsInterface<COUNT>
{
using Base = DemoDisplay;
public:
void initScreen() override;
void redraw() override;
private:
static constexpr int screenHeight = 320, topMargin = 40, bottomMargin = 10, labelOffset = -5;
static constexpr int graphHeight = screenHeight-topMargin-bottomMargin;
Label m_titleLabel{5, 5}; // 230, 25
Graph<200, COUNT> m_graph{0, 40, 270};
};
template<size_t COUNT>
void GraphDisplay<COUNT>::initScreen()
{
tft.fillScreen(TFT_BLACK);
m_titleLabel.start();
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
m_graph.start(static_cast<const MultiStatisticsInterface<COUNT> &>(*this).getBuffers());
}
template<size_t COUNT>
void GraphDisplay<COUNT>::redraw()
{
tft.setTextFont(4);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
m_titleLabel.redraw(text());
m_graph.redraw(static_cast<const MultiStatisticsInterface<COUNT> &>(*this).getBuffers());
}
}

163
src/displays/lockscreen.h Normal file
View File

@ -0,0 +1,163 @@
#pragma once
#include <array>
#include "display.h"
#include "widgets/label.h"
#include "globals.h"
#include "utils.h"
#include "texts.h"
#include "modes/ignoreinputmode.h"
namespace {
class MainMenu;
}
namespace {
class Lockscreen : public Display
{
using Base = Display;
static constexpr auto boxWidth = 35;
static constexpr auto boxHeight = 50;
static constexpr auto spacing = 20;
public:
void start() override;
void initScreen() override;
void update() override {}
void redraw() override;
void stop() override;
void button() override;
void rotate(int offset) override;
private:
void drawRect(int index, int offset, uint32_t color) const;
std::array<Label, 4> m_labels {{
Label{spacing, 100}, // boxWidth, boxHeight
Label{spacing*2+boxWidth, 100}, // boxWidth, boxHeight
Label{spacing*3+boxWidth*2, 100}, // boxWidth, boxHeight
Label{spacing*4+boxWidth*3, 100} // boxWidth, boxHeight
}};
std::array<int8_t, 4> m_numbers;
uint8_t m_currentIndex{};
bool m_pressed;
int m_rotated;
ModeInterface *m_oldMode;
IgnoreInputMode m_mode{0, ControlType::FieldOrientedControl, ControlMode::Speed};
};
void Lockscreen::start()
{
m_numbers = {0,0,0,0};
m_currentIndex = 0;
m_pressed = false;
m_rotated = 0;
m_oldMode = currentMode;
currentMode = &m_mode;
}
void Lockscreen::initScreen()
{
tft.fillScreen(TFT_BLACK);
tft.setTextFont(4);
tft.setTextColor(TFT_YELLOW);
tft.drawString(TEXT_LOCKVEHICLE, 5, 5);
tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE);
tft.setTextColor(TFT_WHITE);
tft.drawString("Enter code to unlock:", 0, 50);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
for(int i = 0; i <= 3; i++)
{
drawRect(i, 3, TFT_WHITE);
drawRect(i, 4, TFT_WHITE);
}
for (auto &label : m_labels)
label.start();
tft.setTextFont(7);
drawRect(0, 1, TFT_YELLOW);
drawRect(0, 2, TFT_YELLOW);
m_labels[0].redraw(String(m_numbers[0]));
}
void Lockscreen::redraw()
{
if (m_pressed)
{
drawRect(m_currentIndex, 1, TFT_BLACK);
drawRect(m_currentIndex, 2, TFT_BLACK);
if (++m_currentIndex>=4)
{
if (m_numbers == decltype(m_numbers){1,2,3,4})
{
switchScreen<MainMenu>();
return;
}
m_numbers = {0,0,0,0};
m_currentIndex = 0;
std::for_each(std::begin(m_labels) + 1, std::end(m_labels), [](auto &label){ label.redraw({}); });
}
m_labels[m_currentIndex].redraw(String{m_numbers[m_currentIndex]});
drawRect(m_currentIndex, 1, TFT_YELLOW);
drawRect(m_currentIndex, 2, TFT_YELLOW);
m_pressed = false;
}
if (m_rotated)
{
m_numbers[m_currentIndex] -= m_rotated;
if (m_numbers[m_currentIndex] < 0)
m_numbers[m_currentIndex]+=10;
else if (m_numbers[m_currentIndex] > 9)
m_numbers[m_currentIndex]-=10;
m_labels[m_currentIndex].redraw(String(m_numbers[m_currentIndex]));
m_rotated = 0;
}
}
void Lockscreen::stop()
{
Base::stop();
if (currentMode == &m_mode)
currentMode = m_oldMode;
}
void Lockscreen::button()
{
m_pressed = true;
}
void Lockscreen::rotate(int offset)
{
m_rotated += offset;
}
void Lockscreen::drawRect(int index, int offset, uint32_t color) const
{
tft.drawRect(m_labels[index].x()-offset, m_labels[index].y()-offset, boxWidth+(offset*2), boxHeight+(offset*2), color);
}
}

View File

@ -0,0 +1,94 @@
#pragma once
#include "demodisplay.h"
#include "actions/switchscreenaction.h"
#include "globals.h"
#include "utils.h"
#include "texts.h"
namespace {
class DemosMenu;
}
namespace {
class MatrixDisplay : public DemoDisplay, public SwitchScreenAction<DemosMenu>
{
using Base = DemoDisplay;
public:
void initScreen() override;
void redraw() override;
void stop() override;
private:
int scroll_slow(int lines, int wait);
static constexpr auto TEXT_HEIGHT = 8; // Height of text to be printed and scrolled
static constexpr auto BOT_FIXED_AREA = 0; // Number of lines in bottom fixed area (lines counted from bottom of screen)
static constexpr auto TOP_FIXED_AREA = 0; // Number of lines in top fixed area (lines counted from top of screen)
uint16_t yStart = TOP_FIXED_AREA;
uint16_t yArea = 320 - TOP_FIXED_AREA - BOT_FIXED_AREA;
uint16_t yDraw = 320 - BOT_FIXED_AREA - TEXT_HEIGHT;
byte pos[42];
uint16_t xPos = 0;
};
void MatrixDisplay::initScreen()
{
tft.setRotation(2);
tft.fillScreen(TFT_BLACK);
setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA);
// First fill the screen with random streaks of characters
for (int j = 0; j < 600; j += TEXT_HEIGHT)
{
for (int i = 0; i < 40; i++)
{
if (pos[i] > 20)
pos[i] -= 3; // Rapid fade initially brightness values
if (pos[i] > 0)
pos[i] -= 1; // Slow fade later
if ((random(20) == 1) && (j<400))
pos[i] = 63; // ~1 in 20 probability of a new character
tft.setTextColor(pos[i] << 5, TFT_BLACK); // Set the green character brightness
if (pos[i] == 63)
tft.setTextColor(TFT_WHITE, TFT_BLACK); // Draw white character
xPos += tft.drawChar(random(32, 128), xPos, yDraw, 1); // Draw the character
}
yDraw = scroll_slow(TEXT_HEIGHT, 14); // Scroll, 14ms per pixel line
xPos = 0;
}
}
void MatrixDisplay::redraw()
{
yDraw = scroll_slow(320,5);
}
void MatrixDisplay::stop()
{
scrollAddress(0);
tft.setRotation(0);
}
int MatrixDisplay::scroll_slow(int lines, int wait)
{
int yTemp = yStart;
for (int i = 0; i < lines; i++) {
yStart++;
if (yStart == 320 - BOT_FIXED_AREA)
yStart = TOP_FIXED_AREA;
scrollAddress(yStart);
delay(wait);
}
return yTemp;
}
}

View File

@ -0,0 +1,48 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "esptexthelpers.h"
#include "texts.h"
namespace {
class SettingsMenu;
}
namespace {
constexpr char TEXT_VERSION[] = "Version: 1.0";
constexpr char TEXT_ESPINFO[] = "ESP info:";
class AboutMenu :
public MenuDisplay,
public StaticText<TEXT_ABOUT>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_VERSION>, DummyAction>,
makeComponent<MenuItem, StaticText<nullptr>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_ESPINFO>, DummyAction>,
makeComponent<MenuItem, EspHeapSizeText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspFreeHeapText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspMinFreeHeapText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspMaxAllocHeapText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspPsramSizeText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspFreePsramText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspMinFreePsramText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspMaxAllocPsramText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspChipRevisionText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspCpuFreqMHzText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspCycleCountText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspSdkVersionText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspFlashChipSizeText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspFlashChipSpeedText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspFlashChipModeText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspSketchSizeText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspSketchMd5Text, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, EspFreeSketchSpaceText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,66 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/wifisoftapenableipv6action.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class WifiSettingsMenu;
}
namespace {
class WifiSoftApGetStationNumText : public virtual TextInterface {
public:
String text() const override { return String{"softAPgetStationNum: "} + WiFi.softAPgetStationNum(); }
};
class WifiSoftApIpText : public virtual TextInterface {
public:
String text() const override { return String{"softAPIP: "} + WiFi.softAPIP().toString(); }
};
class WifiSoftApBroadcastIpText : public virtual TextInterface {
public:
String text() const override { return String{"softAPBroadcastIP: "} + WiFi.softAPBroadcastIP().toString(); }
};
class WifiSoftApNetworkIdText : public virtual TextInterface {
public:
String text() const override { return String{"softAPNetworkID: "} + WiFi.softAPNetworkID().toString(); }
};
class WifiSoftApSubnetCidrText : public virtual TextInterface {
public:
String text() const override { return String{"softAPSubnetCIDR: "} + WiFi.softAPSubnetCIDR(); }
};
class WifiSoftApIpV6Text : public virtual TextInterface {
public:
String text() const override { return String{"softAPIPv6: "} + WiFi.softAPIPv6().toString(); }
};
class WifiSoftApHostnameText : public virtual TextInterface {
public:
String text() const override { return String{"softAPgetHostname: "} + WiFi.softAPgetHostname(); }
};
class WifiSoftApMacAddressText : public virtual TextInterface {
public:
String text() const override { return String{"softAPmacAddress: "} + WiFi.softAPmacAddress(); }
};
class AccessPointWifiSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_ACCESSPOINTWIFISETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, WifiSoftApGetStationNumText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSoftApIpText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSoftApBroadcastIpText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSoftApNetworkIdText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSoftApSubnetCidrText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFISOFTAPENABLEIPV6>, WifiSoftApEnableIpV6Action>,
makeComponent<MenuItem, WifiSoftApIpV6Text, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSoftApHostnameText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSoftApMacAddressText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<WifiSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,39 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/bluetoothbeginaction.h"
#include "actions/bluetoothbeginmasteraction.h"
#include "actions/bluetoothflushaction.h"
#include "actions/bluetoothendaction.h"
#include "actions/bluetoothdisconnectaction.h"
#include "actions/switchscreenaction.h"
#include "bluetoothtexthelpers.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class SettingsMenu;
}
namespace {
class BluetoothSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_BLUETOOTHSETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, BluetoothAvailableText, DisabledColor, DummyAction>,
makeComponent<MenuItem, BluetoothHasClientText, DisabledColor, DummyAction>,
// makeComponent<MenuItem, BluetoothConnectedText, DisabledColor, DummyAction>, // crashes
makeComponent<MenuItem, BluetoothIsReadyText, DisabledColor, DummyAction>,
makeComponent<MenuItem, BluetoothIsReadyMasterText, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BLUETOOTHBEGIN>, BluetoothBeginAction>,
makeComponent<MenuItem, StaticText<TEXT_BLUETOOTHBEGINMASTER>, BluetoothBeginMasterAction>,
makeComponent<MenuItem, StaticText<TEXT_BLUETOOTHFLUSH>, BluetoothFlushAction>,
makeComponent<MenuItem, StaticText<TEXT_BLUETOOTHEND>, BluetoothEndAction>,
makeComponent<MenuItem, StaticText<TEXT_BLUETOOTHDISCONNECT>, BluetoothDisconnectAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/bluetoothconnectbmsaction.h"
#include "actions/bluetoothdisconnectaction.h"
#include "actions/dummyaction.h"
#include "actions/bmsturnonchargeaction.h"
#include "actions/bmsturnoffchargeaction.h"
#include "actions/bmsturnondischargeaction.h"
#include "actions/bmsturnoffdischargeaction.h"
#include "actions/switchscreenaction.h"
#include "bluetoothtexthelpers.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class MainMenu;
}
namespace {
class BmsMenu :
public MenuDisplay,
public StaticText<TEXT_BMS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_CONNECTBMS>, BluetoothConnectBmsAction>,
makeComponent<MenuItem, StaticText<TEXT_DISCONNECTBMS>, BluetoothDisconnectAction>,
makeComponent<MenuItem, BluetoothHasClientText, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_TURNONCHARGE>, BmsTurnOnChargeAction>,
makeComponent<MenuItem, StaticText<TEXT_TURNOFFCHARGE>, BmsTurnOffChargeAction>,
makeComponent<MenuItem, StaticText<TEXT_TURNONDISCHARGE>, BmsTurnOnDischargeAction>,
makeComponent<MenuItem, StaticText<TEXT_TURNOFFDISCHARGE>, BmsTurnOffDischargeAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,55 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "actions/toggleboolaction.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
#include "globals.h"
#include "settingsaccessors.h"
namespace {
class BuzzerMenu;
class SettingsMenu;
}
namespace {
struct FrontFreqAccessor : public RefAccessor<uint8_t> { uint8_t &getRef() const override { return front.command.buzzer.freq; } };
using FrontFreqChangeScreen = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_FRONTFREQ>, FrontFreqAccessor, SwitchScreenAction<BuzzerMenu>>;
struct FrontPatternAccessor : public RefAccessor<uint8_t> { uint8_t &getRef() const override { return front.command.buzzer.pattern; } };
using FrontPatternChangeScreen = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_FRONTPATTERN>, FrontPatternAccessor, SwitchScreenAction<BuzzerMenu>>;
struct BackFreqAccessor : public RefAccessor<uint8_t> { uint8_t &getRef() const override { return back.command.buzzer.freq; } };
using BackFreqChangeScreen = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_BACKFREQ>, BackFreqAccessor, SwitchScreenAction<BuzzerMenu>>;
struct BackPatternAccessor : public RefAccessor<uint8_t> { uint8_t &getRef() const override { return back.command.buzzer.pattern; } };
using BackPatternChangeScreen = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_BACKPATTERN>, BackPatternAccessor, SwitchScreenAction<BuzzerMenu>>;
using ReverseBeepFreq0ChangeScreen = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_REVERSEBEEPFREQ0>, ReverseBeepFreq0Accessor, SwitchScreenAction<BuzzerMenu>>;
using ReverseBeepFreq1ChangeScreen = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_REVERSEBEEPFREQ1>, ReverseBeepFreq1Accessor, SwitchScreenAction<BuzzerMenu>>;
using ReverseBeepDuration0ChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_REVERSEBEEPDURATION0>, ReverseBeepDuration0Accessor, SwitchScreenAction<BuzzerMenu>>;
using ReverseBeepDuration1ChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_REVERSEBEEPDURATION1>, ReverseBeepDuration1Accessor, SwitchScreenAction<BuzzerMenu>>;
class BuzzerMenu :
public MenuDisplay,
public StaticText<TEXT_BUZZER>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_FRONTFREQ>, SwitchScreenAction<FrontFreqChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_FRONTPATTERN>, SwitchScreenAction<FrontPatternChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACKFREQ>, SwitchScreenAction<BackFreqChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACKPATTERN>, SwitchScreenAction<BackPatternChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_REVERSEBEEP>, ToggleBoolAction, CheckboxIcon, ReverseBeepAccessor>,
makeComponent<MenuItem, StaticText<TEXT_REVERSEBEEPFREQ0>, SwitchScreenAction<ReverseBeepFreq0ChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_REVERSEBEEPFREQ1>, SwitchScreenAction<ReverseBeepFreq1ChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_REVERSEBEEPDURATION0>, SwitchScreenAction<ReverseBeepDuration0ChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_REVERSEBEEPDURATION1>, SwitchScreenAction<ReverseBeepDuration1ChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "debugtexthelpers.h"
namespace {
class DebugMenu;
}
namespace {
template<const char *Ttext, typename Ttexts>
class CommandDebugMenu :
public MenuDisplay,
public StaticText<Ttext>,
public StaticMenuDefinition<
makeComponent<MenuItem, typename Ttexts::BuzzerFreqText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::BuzzerPatternText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::PoweroffText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::LedText, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<DebugMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
class FrontCommandDebugMenu : public CommandDebugMenu<TEXT_FRONTCOMMAND, FrontTexts> {};
class BackCommandDebugMenu : public CommandDebugMenu<TEXT_BACKCOMMAND, BackTexts> {};
}

View File

@ -0,0 +1,63 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/loadsettingsaction.h"
#include "actions/savesettingsaction.h"
#include "actions/switchscreenaction.h"
#include "actions/dummyaction.h"
#include "actions/toggleboolaction.h"
#include "icons/lock.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
#include "debugcolorhelpers.h"
namespace {
class MainMenu;
class FrontCommandDebugMenu;
class BackCommandDebugMenu;
class FrontLeftMotorStateDebugMenu;
class FrontRightMotorStateDebugMenu;
class BackLeftMotorStateDebugMenu;
class BackRightMotorStateDebugMenu;
class FrontFeedbackDebugMenu;
class BackFeedbackDebugMenu;
class FrontLeftMotorFeedbackDebugMenu;
class FrontRightMotorFeedbackDebugMenu;
class BackLeftMotorFeedbackDebugMenu;
class BackRightMotorFeedbackDebugMenu;
class DynamicDebugMenu;
}
namespace {
class DebugMenu :
public MenuDisplay,
public StaticText<TEXT_DEBUG>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_LOADSETTINGS>, LoadSettingsAction>,
makeComponent<MenuItem, StaticText<TEXT_SAVESETTINGS>, SaveSettingsAction>,
makeComponent<MenuItem, StaticText<nullptr>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_FRONTCOMMAND>, SwitchScreenAction<FrontCommandDebugMenu>>,
makeComponent<MenuItem, StaticText<TEXT_BACKCOMMAND>, SwitchScreenAction<BackCommandDebugMenu>>,
makeComponent<MenuItem, StaticText<nullptr>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_FRONTLEFTCOMMAND>, SwitchScreenAction<FrontLeftMotorStateDebugMenu>>,
makeComponent<MenuItem, StaticText<TEXT_FRONTRIGHTCOMMAND>, SwitchScreenAction<FrontRightMotorStateDebugMenu>>,
makeComponent<MenuItem, StaticText<TEXT_BACKLEFTCOMMAND>, SwitchScreenAction<BackLeftMotorStateDebugMenu>>,
makeComponent<MenuItem, StaticText<TEXT_BACKRIGHTCOMMAND>, SwitchScreenAction<BackRightMotorStateDebugMenu>>,
makeComponent<MenuItem, StaticText<nullptr>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_FRONTFEEDBACK>, SwitchScreenAction<FrontFeedbackDebugMenu>, FrontFeedbackColor<TFT_WHITE>>,
makeComponent<MenuItem, StaticText<TEXT_BACKFEEDBACK>, SwitchScreenAction<BackFeedbackDebugMenu>, BackFeedbackColor<TFT_WHITE>>,
makeComponent<MenuItem, StaticText<nullptr>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_FRONTLEFTFEEDBACK>, SwitchScreenAction<FrontLeftMotorFeedbackDebugMenu>, FrontFeedbackColor<TFT_WHITE>>,
makeComponent<MenuItem, StaticText<TEXT_FRONTRIGHTFEEDBACK>, SwitchScreenAction<FrontRightMotorFeedbackDebugMenu>, FrontFeedbackColor<TFT_WHITE>>,
makeComponent<MenuItem, StaticText<TEXT_BACKLEFTFEEDBACK>, SwitchScreenAction<BackLeftMotorFeedbackDebugMenu>, BackFeedbackColor<TFT_WHITE>>,
makeComponent<MenuItem, StaticText<TEXT_BACKRIGHTFEEDBACK>, SwitchScreenAction<BackRightMotorFeedbackDebugMenu>, BackFeedbackColor<TFT_WHITE>>,
makeComponent<MenuItem, StaticText<nullptr>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DYNAMICMENU>, SwitchScreenAction<DynamicDebugMenu>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,50 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "menuitem.h"
#include "actions/toggleboolaction.h"
#include "actions/switchscreenaction.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class DefaultModeSettingsMenu;
class ModesSettingsMenu;
}
namespace {
using DefaultModeCtrlTypChangeDisplay = makeComponent<ChangeValueDisplay<ControlType>, StaticText<TEXT_SETCONTROLTYPE>, DefaultModeCtrlTypAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeCtrlModChangeDisplay = makeComponent<ChangeValueDisplay<ControlMode>, StaticText<TEXT_SETCONTROLMODE>, DefaultModeCtrlModAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeSmoothingChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETSMOOTHING>, DefaultModeSmoothingAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeFrontPercentageChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETFRONTPERCENTAGE>, DefaultModeFrontPercentageAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeBackPercentageChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETBACKPERCENTAGE>, DefaultModeBackPercentageAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeAddSchwelleChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETADDSCHWELLE>, DefaultModeAddSchwelleAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeGas1WertChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETGAS1WERT>, DefaultModeGas1WertAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeGas2WertChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETGAS2WERT>, DefaultModeGas2WertAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeBrems1WertChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETBREMS1WERT>, DefaultModeBrems1WertAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
using DefaultModeBrems2WertChangeDisplay = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETBREMS2WERT>, DefaultModeBrems2WertAccessor, SwitchScreenAction<DefaultModeSettingsMenu>>;
class DefaultModeSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_DEFAULTMODESETTIGNS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_SETCONTROLTYPE>, SwitchScreenAction<DefaultModeCtrlTypChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETCONTROLMODE>, SwitchScreenAction<DefaultModeCtrlModChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_ENABLESMOOTHING>, ToggleBoolAction, CheckboxIcon, DefaultModeEnableSmoothingAccessor>,
makeComponent<MenuItem, StaticText<TEXT_SETSMOOTHING>, SwitchScreenAction<DefaultModeSmoothingChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETFRONTPERCENTAGE>, SwitchScreenAction<DefaultModeFrontPercentageChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETBACKPERCENTAGE>, SwitchScreenAction<DefaultModeBackPercentageChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETADDSCHWELLE>, SwitchScreenAction<DefaultModeAddSchwelleChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETGAS1WERT>, SwitchScreenAction<DefaultModeGas1WertChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETGAS2WERT>, SwitchScreenAction<DefaultModeGas2WertChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETBREMS1WERT>, SwitchScreenAction<DefaultModeBrems1WertChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETBREMS2WERT>, SwitchScreenAction<DefaultModeBrems2WertChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<ModesSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class StarfieldDisplay;
class PingPongDisplay;
class SpiroDisplay;
class GameOfLifeDisplay;
class MatrixDisplay;
class MainMenu;
}
namespace {
class DemosMenu :
public MenuDisplay,
public StaticText<TEXT_DEMOS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_STARFIELD>, SwitchScreenAction<StarfieldDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_PINGPONG>, SwitchScreenAction<PingPongDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SPIRO>, SwitchScreenAction<SpiroDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_GAMEOFLIFE>, SwitchScreenAction<GameOfLifeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_MATRIX>, SwitchScreenAction<MatrixDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,153 @@
#pragma once
#include <Arduino.h>
#include <WString.h>
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "actions/dummyaction.h"
#include "actions/toggleboolaction.h"
#include "icons/lock.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class DebugMenu;
}
namespace {
class RandomText : public virtual TextInterface
{
public:
String text() const override
{
const auto now = millis();
if (!m_nextUpdate || now >= m_nextUpdate)
{
m_title = String{"Dynamic text: "} + random(0, 100);
m_nextUpdate = now + random(0, 1000);
}
return m_title;
}
private:
mutable unsigned long m_nextUpdate{};
mutable String m_title;
};
class RandomColor : public virtual ColorInterface
{
public:
int color() const override
{
const auto now = millis();
if (!m_nextUpdate || now >= m_nextUpdate)
{
const auto count = std::distance(std::begin(default_4bit_palette), std::end(default_4bit_palette));
m_color = default_4bit_palette[random(0, count)];
m_nextUpdate = now + random(0, 1000);
}
return m_color;
}
private:
mutable unsigned long m_nextUpdate{};
mutable int m_color;
};
class RandomFont : public virtual FontInterface
{
public:
int font() const override
{
const auto now = millis();
if (!m_nextUpdate || now >= m_nextUpdate)
{
m_font = random(1, 5);
m_nextUpdate = now + random(0, 1000);
}
return m_font;
}
private:
mutable unsigned long m_nextUpdate{};
mutable int m_font;
};
class RandomIcon : public virtual MenuItemIconInterface
{
public:
const MenuItemIcon *icon() const override
{
const auto now = millis();
if (!m_nextUpdate || now >= m_nextUpdate)
{
if (m_icon)
m_icon = nullptr;
else
m_icon = &icons::lock;
m_nextUpdate = now + random(0, 1000);
}
return m_icon;
}
private:
mutable unsigned long m_nextUpdate{};
mutable const Icon<24, 24> *m_icon;
};
bool toggle;
struct ToggleAccessor : public virtual RefAccessor<bool>
{
public:
bool &getRef() const override { return toggle; }
};
constexpr char TEXT_DUMMYITEM[] = "Dummy item";
constexpr char TEXT_DYNAMICCOLOR[] = "Dynamic color";
constexpr char TEXT_DYNAMICFONT[] = "Dynamic font";
constexpr char TEXT_DYNAMICICON[] = "Dynamic icon";
constexpr char TEXT_STATICICON[] = "Static icon";
constexpr char TEXT_DEBUGTOGGLE[] = "Toggle";
class DynamicDebugMenu :
public MenuDisplay,
public RandomText,
public StaticMenuDefinition<
// dummy items to allow for scrolling
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
// the interesting bits
makeComponent<MenuItem, RandomText, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DYNAMICCOLOR>, RandomColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DYNAMICFONT>, RandomFont, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DYNAMICICON>, RandomIcon, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_STATICICON>, StaticMenuItemIcon<&icons::lock>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DEBUGTOGGLE>, ToggleBoolAction, CheckboxIcon, ToggleAccessor>,
makeComponent<MenuItem, RandomText, RandomColor, RandomFont, RandomIcon, DummyAction>,
// more scrolling
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_DUMMYITEM>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<DebugMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/toggleboolaction.h"
#include "actions/switchscreenaction.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class HardwareSettingsMenu;
}
namespace {
class EnableMenu :
public MenuDisplay,
public StaticText<TEXT_SETENABLED>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_ENABLEFRONTLEFT>, ToggleBoolAction, CheckboxIcon, FrontLeftEnabledAccessor>,
makeComponent<MenuItem, StaticText<TEXT_ENABLEFRONTRIGHT>, ToggleBoolAction, CheckboxIcon, FrontRightEnabledAccessor>,
makeComponent<MenuItem, StaticText<TEXT_ENABLEBACKLEFT>, ToggleBoolAction, CheckboxIcon, BackLeftEnabledAccessor>,
makeComponent<MenuItem, StaticText<TEXT_ENABLEBACKRIGHT>, ToggleBoolAction, CheckboxIcon, BackRightEnabledAccessor>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<HardwareSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "debugtexthelpers.h"
#include "debugcolorhelpers.h"
namespace {
class DebugMenu;
}
namespace {
template<const char *Ttext, typename Ttexts, template<int> class ColorInterface>
class FeedbackDebugMenu :
public MenuDisplay,
public StaticText<Ttext>,
public StaticMenuDefinition<
makeComponent<MenuItem, typename Ttexts::BatVoltageText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::BatVoltageFixedText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::BoardTempText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::BoardTempFixedText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::TimeoutCntSerialText, StaticFont<2>, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<DebugMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
class FrontFeedbackDebugMenu : public FeedbackDebugMenu<TEXT_FRONTFEEDBACK, FrontTexts, FrontFeedbackColor> {};
class BackFeedbackDebugMenu : public FeedbackDebugMenu<TEXT_BACKFEEDBACK, BackTexts, FrontFeedbackColor> {}; }

View File

@ -0,0 +1,79 @@
#pragma once
#include <HardwareSerial.h>
#include <WiFi.h>
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "changevaluedisplay.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/toggleboolaction.h"
#include "actions/switchscreenaction.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class GenericWifiSettingsMenu;
class WifiSettingsMenu;
}
namespace {
struct WifiStatusBitsText : public virtual TextInterface {
public:
String text() const override { return String{"statusBits: "} + WiFi.getStatusBits(); }
};
struct WifiChannelText : public virtual TextInterface {
public:
String text() const override { return String{"channel: "} + WiFi.channel(); }
};
struct WifiModeAccessor : public virtual AccessorInterface<wifi_mode_t>
{
wifi_mode_t getValue() const override { return WiFi.getMode(); }
void setValue(wifi_mode_t value) override
{
if (!WiFi.mode(value))
Serial.println("Could not change WiFi mode!");
// TODO: better error handling
}
};
using WifiModeChangeScreen = makeComponent<ChangeValueDisplay<wifi_mode_t>, StaticText<TEXT_WIFICHANGEMODE>, WifiModeAccessor, SwitchScreenAction<GenericWifiSettingsMenu>>;
struct WifiSleepAccessor : public virtual AccessorInterface<bool>
{
bool getValue() const override { return WiFi.getSleep(); }
void setValue(bool value) override
{
if (!WiFi.setSleep(value))
Serial.println("Could not set WiFi sleep!");
// TODO: better error handling
}
};
struct WifiTxPowerAccessor : public virtual AccessorInterface<wifi_power_t>
{
wifi_power_t getValue() const override { return WiFi.getTxPower(); }
void setValue(wifi_power_t value) override
{
if (!WiFi.setTxPower(value))
Serial.println("Could not set WiFi tx power!");
// TODO: better error handling
}
};
using WifiTxPowerChangeScreen = makeComponent<ChangeValueDisplay<wifi_power_t>, StaticText<TEXT_WIFICHANGETXPOWER>, WifiTxPowerAccessor, SwitchScreenAction<GenericWifiSettingsMenu>>;
class GenericWifiSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_GENERICWIFISETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, WifiStatusBitsText, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiChannelText, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFICHANGEMODE>, SwitchScreenAction<WifiModeChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_WIFICHANGESLEEP>, ToggleBoolAction, CheckboxIcon, WifiSleepAccessor>,
makeComponent<MenuItem, StaticText<TEXT_WIFICHANGETXPOWER>, SwitchScreenAction<WifiTxPowerChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<WifiSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,69 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "displays/graphdisplay.h"
#include "statistics.h"
namespace {
class MainMenu;
class DualGraphDisplay;
}
namespace {
using GasGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_GAS>, MultiStatisticsSingleImpl, GasStatistics>;
using BremsGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_BREMS>, MultiStatisticsSingleImpl, BremsStatistics>;
using AvgSpeedGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_AVGSPEED>, MultiStatisticsSingleImpl, AvgSpeedStatistics>;
using AvgSpeedKmhGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_AVGSPEEDKMH>, MultiStatisticsSingleImpl, AvgSpeedKmhStatistics>;
using SumCurrentGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_SUMCURRENT>, MultiStatisticsSingleImpl, SumCurrentStatistics>;
using SumAbsoluteCurrentGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_SUMABSOLUTECURRENT>, MultiStatisticsSingleImpl, SumAbsoluteCurrentStatistics>;
using FrontVoltageGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_FRONTVOLTAGE>, MultiStatisticsSingleImpl, FrontVoltageStatistics>;
using BackVoltageGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_BACKVOLTAGE>, MultiStatisticsSingleImpl, BackVoltageStatistics>;
using BmsVoltageGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_BMSVOLTAGE>, MultiStatisticsSingleImpl, BmsVoltageStatistics>;
using BmsCurrentGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_BMSCURRENT>, MultiStatisticsSingleImpl, BmsCurrentStatistics>;
using BmsPowerGraphDisplay = makeComponent<GraphDisplay<1>, StaticText<TEXT_BMSPOWER>, MultiStatisticsSingleImpl, BmsPowerStatistics>;
class SumCurrentsComparisonStatistics : public virtual MultiStatisticsInterface<2>
{
std::array<std::reference_wrapper<const statistics::ContainerType>, 2> getBuffers() const override
{
return {SumCurrentStatistics{}.getBuffer(), BmsCurrentStatistics{}.getBuffer()};
}
};
using SumCurrentsComparisonGraphDisplay = makeComponent<GraphDisplay<2>, StaticText<TEXT_SUMCURRENTSCOMPARISON>, SumCurrentsComparisonStatistics>;
class MotorCurrentsStatistics : public virtual MultiStatisticsInterface<4>
{
std::array<std::reference_wrapper<const statistics::ContainerType>, 4> getBuffers() const override
{
return {FrontLeftCurrentStatistics{}.getBuffer(), FrontRightCurrentStatistics{}.getBuffer(), BackLeftCurrentStatistics{}.getBuffer(), BackRightCurrentStatistics{}.getBuffer()};
}
};
using MotorCurrentsGraphDisplay = makeComponent<GraphDisplay<4>, StaticText<TEXT_MOTORCURRENTS>, MotorCurrentsStatistics>;
class GraphsMenu :
public MenuDisplay,
public StaticText<TEXT_GRAPHS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_GAS>, SwitchScreenAction<GasGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BREMS>, SwitchScreenAction<BremsGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_AVGSPEED>, SwitchScreenAction<AvgSpeedGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_AVGSPEEDKMH>, SwitchScreenAction<AvgSpeedKmhGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SUMCURRENT>, SwitchScreenAction<SumCurrentGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SUMABSOLUTECURRENT>, SwitchScreenAction<SumAbsoluteCurrentGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_FRONTVOLTAGE>, SwitchScreenAction<FrontVoltageGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BACKVOLTAGE>, SwitchScreenAction<BackVoltageGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BMSVOLTAGE>, SwitchScreenAction<BmsVoltageGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BMSCURRENT>, SwitchScreenAction<BmsCurrentGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BMSPOWER>, SwitchScreenAction<BmsPowerGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SUMCURRENTSCOMPARISON>, SwitchScreenAction<SumCurrentsComparisonGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_MOTORCURRENTS>, SwitchScreenAction<MotorCurrentsGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_DUALGRAPHS>, SwitchScreenAction<DualGraphDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <ratio>
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "actions/toggleboolaction.h"
#include "actions/switchscreenaction.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
#include "globals.h"
#include "settingsaccessors.h"
namespace {
class HardwareSettingsMenu;
class PotiSettingsMenu;
class EnableMenu;
class InvertMenu;
class SettingsMenu;
}
namespace {
using WheelDiameterMmChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_WHEELDIAMETERMM>, WheelDiameterMmAccessor, SwitchScreenAction<HardwareSettingsMenu>>;
using WheelDiameterInchChangeScreen = makeComponent<ChangeValueDisplay<float>, StaticText<TEXT_WHEELDIAMETERINCH>, WheelDiameterInchAccessor, RatioNumberStep<float, std::ratio<1,10>>, SwitchScreenAction<HardwareSettingsMenu>>;
using NumMagnetPolesChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_NUMMAGNETPOLES>, NumMagnetPolesAccessor, SwitchScreenAction<HardwareSettingsMenu>>;
class HardwareSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_HARDWARESETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_SETENABLED>, SwitchScreenAction<EnableMenu>>,
makeComponent<MenuItem, StaticText<TEXT_SETINVERTED>, SwitchScreenAction<InvertMenu>>,
makeComponent<MenuItem, StaticText<TEXT_POTISETTINGS>, SwitchScreenAction<PotiSettingsMenu>>,
makeComponent<MenuItem, StaticText<TEXT_WHEELDIAMETERMM>, SwitchScreenAction<WheelDiameterMmChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_WHEELDIAMETERINCH>, SwitchScreenAction<WheelDiameterInchChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_NUMMAGNETPOLES>, SwitchScreenAction<NumMagnetPolesChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SWAPFRONTBACK>, ToggleBoolAction, CheckboxIcon, SwapFrontBackAccessor>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/toggleboolaction.h"
#include "actions/switchscreenaction.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class HardwareSettingsMenu;
}
namespace {
class InvertMenu :
public MenuDisplay,
public StaticText<TEXT_SETINVERTED>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_INVERTFRONTLEFT>, ToggleBoolAction, CheckboxIcon, FrontLeftInvertedAccessor>,
makeComponent<MenuItem, StaticText<TEXT_INVERTFRONTRIGHT>, ToggleBoolAction, CheckboxIcon, FrontRightInvertedAccessor>,
makeComponent<MenuItem, StaticText<TEXT_INVERTBACKLEFT>, ToggleBoolAction, CheckboxIcon, BackLeftInvertedAccessor>,
makeComponent<MenuItem, StaticText<TEXT_INVERTBACKRIGHT>, ToggleBoolAction, CheckboxIcon, BackRightInvertedAccessor>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<HardwareSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class LarsmModeSettingsMenu;
class ModesSettingsMenu;
}
namespace {
using LarsmModeModeChangeDisplay = makeComponent<ChangeValueDisplay<LarsmModeMode>, StaticText<TEXT_LARSMMODECHANGEMODE>, LarsmModeModeAccessor, SwitchScreenAction<LarsmModeSettingsMenu>>;
using LarsmModeIterationsChangeDisplay = makeComponent<ChangeValueDisplay<uint8_t>, StaticText<TEXT_LARSMMODECHANGEITERATIONS>, LarsmModeIterationsAccessor, SwitchScreenAction<LarsmModeSettingsMenu>>;
class LarsmModeSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_LARSMMODESETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_LARSMMODECHANGEMODE>, SwitchScreenAction<LarsmModeModeChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_LARSMMODECHANGEITERATIONS>, SwitchScreenAction<LarsmModeIterationsChangeDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<ModesSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,39 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class LimitsSettingsMenu;
class SettingsMenu;
}
namespace {
using IMotMaxChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETIMOTMAX>, IMotMaxAccessor, SwitchScreenAction<LimitsSettingsMenu>>;
using IDcMaxChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETIDCMAX>, IDcMaxAccessor, SwitchScreenAction<LimitsSettingsMenu>>;
using NMotMaxKmhChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETNMOTMAXKMH>, NMotMaxKmhAccessor, SwitchScreenAction<LimitsSettingsMenu>>;
using NMotMaxRpmChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETNMOTMAX>, NMotMaxRpmAccessor, SwitchScreenAction<LimitsSettingsMenu>>;
using FieldWeakMaxChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETFIELDWEAKMAX>, FieldWeakMaxAccessor, SwitchScreenAction<LimitsSettingsMenu>>;
using PhaseAdvMaxChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETPHASEADVMAX>, PhaseAdvMaxAccessor, SwitchScreenAction<LimitsSettingsMenu>>;
class LimitsSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_LIMITSSETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_SETIMOTMAX>, SwitchScreenAction<IMotMaxChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETIDCMAX>, SwitchScreenAction<IDcMaxChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETNMOTMAXKMH>, SwitchScreenAction<NMotMaxKmhChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETNMOTMAX>, SwitchScreenAction<NMotMaxRpmChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETFIELDWEAKMAX>, SwitchScreenAction<FieldWeakMaxChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETPHASEADVMAX>, SwitchScreenAction<PhaseAdvMaxChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,51 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "actions/rebootaction.h"
#include "texts.h"
#include "icons/back.h"
#include "icons/modes.h"
#include "icons/presets.h"
#include "icons/graph.h"
#include "icons/bms.h"
#include "icons/settings.h"
#include "icons/lock.h"
#include "icons/demos.h"
#include "icons/poweroff.h"
#include "icons/reboot.h"
namespace {
class StatusDisplay;
class SelectModeMenu;
class PresetsMenu;
class GraphsMenu;
class BmsMenu;
class SettingsMenu;
class Lockscreen;
class DemosMenu;
class PoweroffDisplay;
class DebugMenu;
}
namespace {
class MainMenu :
public MenuDisplay,
public StaticText<TEXT_MAINMENU>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_STATUS>, SwitchScreenAction<StatusDisplay>, StaticMenuItemIcon<&icons::back>>,
makeComponent<MenuItem, StaticText<TEXT_SELECTMODE>, SwitchScreenAction<SelectModeMenu>, StaticMenuItemIcon<&icons::modes>>,
makeComponent<MenuItem, StaticText<TEXT_PRESETS>, SwitchScreenAction<PresetsMenu>, StaticMenuItemIcon<&icons::presets>>,
makeComponent<MenuItem, StaticText<TEXT_GRAPHS>, SwitchScreenAction<GraphsMenu>, StaticMenuItemIcon<&icons::graph>>,
makeComponent<MenuItem, StaticText<TEXT_BMS>, SwitchScreenAction<BmsMenu>, StaticMenuItemIcon<&icons::bms>>,
makeComponent<MenuItem, StaticText<TEXT_SETTINGS>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::settings>>,
makeComponent<MenuItem, StaticText<TEXT_LOCKVEHICLE>, SwitchScreenAction<Lockscreen>, StaticMenuItemIcon<&icons::lock>>,
makeComponent<MenuItem, StaticText<TEXT_DEMOS>, SwitchScreenAction<DemosMenu>, StaticMenuItemIcon<&icons::demos>>,
makeComponent<MenuItem, StaticText<TEXT_POWEROFF>, SwitchScreenAction<PoweroffDisplay>, StaticMenuItemIcon<&icons::poweroff>>,
makeComponent<MenuItem, StaticText<TEXT_REBOOT>, RebootAction, StaticMenuItemIcon<&icons::reboot>>,
makeComponent<MenuItem, StaticText<TEXT_DEBUG>, SwitchScreenAction<DebugMenu>>
>
{};
};

View File

@ -0,0 +1,28 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class DefaultModeSettingsMenu;
class TempomatModeSettingsMenu;
class LarsmModeSettingsMenu;
class SettingsMenu;
}
namespace {
class ModesSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_MODESSETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_DEFAULTMODESETTIGNS>, SwitchScreenAction<DefaultModeSettingsMenu>>,
makeComponent<MenuItem, StaticText<TEXT_TEMPOMATMODESETTINGS>, SwitchScreenAction<TempomatModeSettingsMenu>>,
makeComponent<MenuItem, StaticText<TEXT_LARSMMODESETTINGS>, SwitchScreenAction<LarsmModeSettingsMenu>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "debugtexthelpers.h"
#include "debugcolorhelpers.h"
namespace {
class DebugMenu;
}
namespace {
template<const char *Ttext, typename Ttexts, template<int> class ColorInterface>
class MotorFeedbackDebugMenu :
public MenuDisplay,
public StaticText<Ttext>,
public StaticMenuDefinition<
makeComponent<MenuItem, typename Ttexts::AngleText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::SpeedText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::SpeedKmhText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::ErrorText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::CurrentText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::CurrentFixedText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::ChopsText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, typename Ttexts::HallText, ColorInterface<TFT_DARKGREY>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<DebugMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
class FrontLeftMotorFeedbackDebugMenu : public MotorFeedbackDebugMenu<TEXT_FRONTLEFTFEEDBACK, FrontTexts::LeftFeedback, FrontFeedbackColor> {};
class FrontRightMotorFeedbackDebugMenu : public MotorFeedbackDebugMenu<TEXT_FRONTRIGHTFEEDBACK, FrontTexts::RightFeedback, FrontFeedbackColor> {};
class BackLeftMotorFeedbackDebugMenu : public MotorFeedbackDebugMenu<TEXT_BACKLEFTFEEDBACK, BackTexts::LeftFeedback, BackFeedbackColor> {};
class BackRightMotorFeedbackDebugMenu : public MotorFeedbackDebugMenu<TEXT_BACKRIGHTFEEDBACK, BackTexts::RightFeedback, BackFeedbackColor> {};
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "debugtexthelpers.h"
namespace {
class DebugMenu;
}
namespace {
template<const char *Ttext, typename Ttexts>
class MotorStateDebugMenu :
public MenuDisplay,
public StaticText<Ttext>,
public StaticMenuDefinition<
makeComponent<MenuItem, typename Ttexts::EnableText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::PwmText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::CtrlTypText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::CtrlModText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::IMotMaxText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::IDcMaxText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::NMotMaxText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::FieldWeakMaxText, DisabledColor, DummyAction>,
makeComponent<MenuItem, typename Ttexts::PhaseAdvMaxText, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<DebugMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
class FrontLeftMotorStateDebugMenu : public MotorStateDebugMenu<TEXT_FRONTLEFTCOMMAND, FrontTexts::LeftCommand> {};
class FrontRightMotorStateDebugMenu : public MotorStateDebugMenu<TEXT_FRONTRIGHTCOMMAND, FrontTexts::RightCommand> {};
class BackLeftMotorStateDebugMenu : public MotorStateDebugMenu<TEXT_BACKLEFTCOMMAND, BackTexts::LeftCommand> {};
class BackRightMotorStateDebugMenu : public MotorStateDebugMenu<TEXT_BACKRIGHTCOMMAND, BackTexts::RightCommand> {};
}

View File

@ -0,0 +1,50 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class PotiSettingsMenu;
class CalibrateDisplay;
class HardwareSettingsMenu;
}
namespace {
struct GasText : public virtual TextInterface {
public:
String text() const override { return String{"gas: "} + raw_gas + ": " + gas; }
};
struct BremsText : public virtual TextInterface {
public:
String text() const override { return String{"brems: "} + raw_brems + ": " + brems; }
};
using SampleCountChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETSAMPLECOUNT>, SampleCountAccessor, SwitchScreenAction<PotiSettingsMenu>>;
using GasMinChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETGASMIN>, GasMinAccessor, SwitchScreenAction<PotiSettingsMenu>>;
using GasMaxChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETGASMAX>, GasMaxAccessor, SwitchScreenAction<PotiSettingsMenu>>;
using BremsMinChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETBREMSMIN>, BremsMinAccessor, SwitchScreenAction<PotiSettingsMenu>>;
using BremsMaxChangeScreen = makeComponent<ChangeValueDisplay<int16_t>, StaticText<TEXT_SETBREMSMAX>, BremsMaxAccessor, SwitchScreenAction<PotiSettingsMenu>>;
class PotiSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_POTISETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, GasText, DisabledColor, StaticFont<2>, DummyAction>,
makeComponent<MenuItem, BremsText, DisabledColor, StaticFont<2>, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_CALIBRATE>, SwitchScreenAction<CalibrateDisplay>>,
makeComponent<MenuItem, StaticText<TEXT_SETSAMPLECOUNT>, SwitchScreenAction<SampleCountChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETGASMIN>, SwitchScreenAction<GasMinChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETGASMAX>, SwitchScreenAction<GasMaxChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETBREMSMIN>, SwitchScreenAction<BremsMinChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETBREMSMAX>, SwitchScreenAction<BremsMaxChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<HardwareSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,48 @@
#pragma once
#include "actioninterface.h"
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "settings.h"
#include "presets.h"
#include "globals.h"
namespace {
class MainMenu;
}
namespace {
template<const Settings *preset>
class ApplyPresetAction : public virtual ActionInterface {public: void triggered() override { settings = *preset; saveSettings(); } };
template<const Settings::Limits *preset>
class ApplyLimitsPresetAction : public virtual ActionInterface {public: void triggered() override { settings.limits = *preset; saveSettings(); } };
template<const Settings::Hardware::Poti *preset>
class ApplyPotiPresetAction : public virtual ActionInterface {public: void triggered() override { settings.hardware.poti = *preset; saveSettings(); } };
template<const Settings::Hardware *preset>
class ApplyHardwarePresetAction : public virtual ActionInterface {public: void triggered() override { settings.hardware = *preset; saveSettings(); } };
class PresetsMenu :
public MenuDisplay,
public StaticText<TEXT_PRESETS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_DEFAULTEVERYTHING>, ApplyPresetAction<&presets::defaultSettings>>,
makeComponent<MenuItem, StaticText<TEXT_DEFAULTLIMITS>, ApplyLimitsPresetAction<&presets::defaultLimits>>,
makeComponent<MenuItem, StaticText<TEXT_KIDSLIMITS>, ApplyLimitsPresetAction<&presets::kidsLimits>>,
makeComponent<MenuItem, StaticText<TEXT_DEFAULTPOTI>, ApplyPotiPresetAction<&presets::defaultPoti>>,
makeComponent<MenuItem, StaticText<TEXT_DEFAULTHARDWARE>, ApplyHardwarePresetAction<&presets::defaultHardware>>,
makeComponent<MenuItem, StaticText<TEXT_STREET>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_SIDEWALK>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_POLICE>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_RACE>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,63 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/multiaction.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "globals.h"
#include "modes/defaultmode.h"
#include "modes/tempomatmode.h"
#include "modes/larsmmode.h"
namespace {
class MainMenu;
}
namespace {
template<typename T1, T1 &target, typename T2, T2 value>
class SetterAction : public ActionInterface
{
public:
void triggered() override { target = value; }
};
using SetDefaultModeAction = SetterAction<ModeInterface*, currentMode, DefaultMode*, &modes::defaultMode>;
using SetTempomatModeAction = SetterAction<ModeInterface*, currentMode, TempomatMode*, &modes::tempomatMode>;
using SetLarsmModeAction = SetterAction<ModeInterface*, currentMode, LarsmMode*, &modes::larsmMode>;
class SelectModeMenu :
public MenuDisplay,
public StaticText<TEXT_SELECTMODE>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_DEFAULT>, MultiAction<SetDefaultModeAction, SwitchScreenAction<MainMenu>>>,
makeComponent<MenuItem, StaticText<TEXT_TEMPOMAT>, MultiAction<SetTempomatModeAction, SwitchScreenAction<MainMenu>>>,
makeComponent<MenuItem, StaticText<TEXT_LARSM>, MultiAction<SetLarsmModeAction, SwitchScreenAction<MainMenu>>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{
using Base = MenuDisplay;
public:
void start() override;
};
void SelectModeMenu::start()
{
Base::start();
if (currentMode == &modes::defaultMode)
setSelectedIndex(0);
else if (currentMode == &modes::tempomatMode)
setSelectedIndex(1);
else if (currentMode == &modes::larsmMode)
setSelectedIndex(2);
else
{
Serial.printf("Unknown mode: %s", currentMode?currentMode->displayName():"");
setSelectedIndex(3);
}
}
}

View File

@ -0,0 +1,53 @@
#pragma once
#include <HardwareSerial.h>
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "actions/toggleboolaction.h"
#include "actions/switchscreenaction.h"
#include "checkboxicon.h"
#include "icons/wifi.h"
#include "icons/bluetooth.h"
#include "icons/hardware.h"
#include "icons/buzzer.h"
#include "icons/info.h"
#include "icons/back.h"
#include "texts.h"
#include "globals.h"
#include "settingsaccessors.h"
namespace {
class LimitsSettingsMenu;
class WifiSettingsMenu;
class BluetoothSettingsMenu;
class ModesSettingsMenu;
class HardwareSettingsMenu;
class BuzzerMenu;
class AboutMenu;
class MainMenu;
}
namespace {
struct FrontLedAccessor : public RefAccessor<bool> { bool &getRef() const override { return front.command.led; } };
struct BackLedAccessor : public RefAccessor<bool> { bool &getRef() const override { return back.command.led; } };
class SettingsMenu :
public MenuDisplay,
public StaticText<TEXT_SETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_LIMITSSETTINGS>, SwitchScreenAction<LimitsSettingsMenu>>,
makeComponent<MenuItem, StaticText<TEXT_WIFISETTINGS>, SwitchScreenAction<WifiSettingsMenu>, StaticMenuItemIcon<&icons::wifi>>,
makeComponent<MenuItem, StaticText<TEXT_BLUETOOTHSETTINGS>, SwitchScreenAction<BluetoothSettingsMenu>, StaticMenuItemIcon<&icons::bluetooth>>,
makeComponent<MenuItem, StaticText<TEXT_MODESSETTINGS>, SwitchScreenAction<ModesSettingsMenu>>,
makeComponent<MenuItem, StaticText<TEXT_HARDWARESETTINGS>, SwitchScreenAction<HardwareSettingsMenu>, StaticMenuItemIcon<&icons::hardware>>,
makeComponent<MenuItem, StaticText<TEXT_AUTOCONNECTBMS>, ToggleBoolAction, CheckboxIcon, AutoConnectBmsAccessor>,
makeComponent<MenuItem, StaticText<TEXT_BUZZER>, SwitchScreenAction<BuzzerMenu>, StaticMenuItemIcon<&icons::buzzer>>,
makeComponent<MenuItem, StaticText<TEXT_FRONTLED>, ToggleBoolAction, CheckboxIcon, FrontLedAccessor>,
makeComponent<MenuItem, StaticText<TEXT_BACKLED>, ToggleBoolAction, CheckboxIcon, BackLedAccessor>,
makeComponent<MenuItem, StaticText<TEXT_ABOUT>, SwitchScreenAction<AboutMenu>, StaticMenuItemIcon<&icons::info>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,140 @@
#pragma once
#include <WiFi.h>
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "menuitem.h"
#include "actions/dummyaction.h"
#include "actions/switchscreenaction.h"
#include "actions/wifireconnectaction.h"
#include "actions/wifidisconnectaction.h"
#include "actions/toggleboolaction.h"
#include "actions/wifienableipv6action.h"
#include "checkboxicon.h"
#include "icons/back.h"
#include "texts.h"
namespace {
class WifiSettingsMenu;
}
namespace {
struct WifiIsConnectedText : public virtual TextInterface {
public:
String text() const override { return String{"isConnected: "} + (WiFi.isConnected() ? "true" : "false"); }
};
struct WifiAutoConnectAccessor : public virtual AccessorInterface<bool>
{
bool getValue() const override { return WiFi.getAutoConnect(); }
void setValue(bool value) override
{
if (!WiFi.setAutoConnect(value))
Serial.println("Could not set WiFi autoConnect!");
// TODO: better error handling
}
};
struct WifiAutoReconnectAccessor : public virtual AccessorInterface<bool>
{
bool getValue() const override { return WiFi.getAutoReconnect(); }
void setValue(bool value) override
{
if (!WiFi.setAutoReconnect(value))
Serial.println("Could not set WiFi autoReconnect!");
// TODO: better error handling
}
};
struct WifiLocalIpText : public virtual TextInterface {
public:
String text() const override { return String{"localIP: "} + WiFi.localIP().toString(); }
};
struct WifiMacAddressText : public virtual TextInterface {
public:
String text() const override { return String{"macAddress: "} + WiFi.macAddress(); }
};
struct WifiSubnetMaskText : public virtual TextInterface {
public:
String text() const override { return String{"subnetMask: "} + WiFi.subnetMask().toString(); }
};
struct WifiGatewayIpText : public virtual TextInterface {
public:
String text() const override { return String{"gatewayIP: "} + WiFi.gatewayIP().toString(); }
};
struct WifiDnsIpText : public virtual TextInterface {
public:
String text() const override { return String{"dnsIP: "} + WiFi.dnsIP().toString(); }
};
struct WifiBroadcastIpText : public virtual TextInterface {
public:
String text() const override { return String{"broadcastIP: "} + WiFi.broadcastIP().toString(); }
};
struct WifiNetworkIdText : public virtual TextInterface {
public:
String text() const override { return String{"networkID: "} + WiFi.networkID().toString(); }
};
struct WifiSubnetCIDRText : public virtual TextInterface {
public:
String text() const override { return String{"subnetCIDR: "} + WiFi.subnetCIDR(); }
};
struct WifiLocalIpV6Text : public virtual TextInterface {
public:
String text() const override { return String{"localIPv6: "} + WiFi.localIPv6().toString(); }
};
struct WifiHostnameText : public virtual TextInterface {
public:
String text() const override { return String{"hostname: "} + WiFi.getHostname(); }
};
struct WifiStatusText : public virtual TextInterface {
public:
String text() const override { return String{"status: "} + toString(WiFi.status()); }
};
struct WifiSsidText : public virtual TextInterface {
public:
String text() const override { return String{"SSID: "} + WiFi.SSID(); }
};
struct WifiPskText : public virtual TextInterface {
public:
String text() const override { return String{"psk: "} + WiFi.psk(); }
};
struct WifiBssidText : public virtual TextInterface {
public:
String text() const override { return String{"BSSID: "} + WiFi.BSSIDstr(); }
};
struct WifiRssiText : public virtual TextInterface {
public:
String text() const override { return String{"RSSI: "} + WiFi.RSSI(); }
};
class StationWifiSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_STATIONWIFISETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_WIFIRECONNECT>, WifiReconnectAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFIDISCONNECT>, WifiDisconnectAction>,
makeComponent<MenuItem, WifiIsConnectedText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFICHANGEAUTOCONNECT>, ToggleBoolAction, CheckboxIcon, WifiAutoConnectAccessor>,
makeComponent<MenuItem, StaticText<TEXT_WIFICHANGEAUTORECONNECT>, ToggleBoolAction, CheckboxIcon, WifiAutoReconnectAccessor>,
makeComponent<MenuItem, WifiLocalIpText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiMacAddressText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSubnetMaskText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiGatewayIpText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiDnsIpText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiBroadcastIpText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiNetworkIdText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSubnetCIDRText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_WIFIENABLEIPV6>, WifiEnableIpV6Action>,
makeComponent<MenuItem, WifiLocalIpV6Text, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiHostnameText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiStatusText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiSsidText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiPskText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiBssidText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, WifiRssiText, StaticFont<2>, DisabledColor, DummyAction>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<WifiSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "menudisplay.h"
#include "staticmenudefinition.h"
#include "utils.h"
#include "changevaluedisplay.h"
#include "menuitem.h"
#include "actions/switchscreenaction.h"
#include "icons/back.h"
#include "texts.h"
#include "settingsaccessors.h"
namespace {
class TempomatModeSettingsMenu;
class ModesSettingsMenu;
}
namespace {
using TempomatModeCtrlTypChangeScreen = makeComponent<ChangeValueDisplay<ControlType>, StaticText<TEXT_SETCONTROLMODE>, TempomatModeCtrlTypAccessor, SwitchScreenAction<TempomatModeSettingsMenu>>;
using TempomatModeCtrlModChangeScreen = makeComponent<ChangeValueDisplay<ControlMode>, StaticText<TEXT_SETCONTROLMODE>, TempomatModeCtrlModAccessor, SwitchScreenAction<TempomatModeSettingsMenu>>;
class TempomatModeSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_TEMPOMATMODESETTINGS>,
public StaticMenuDefinition<
makeComponent<MenuItem, StaticText<TEXT_SETCONTROLTYPE>, SwitchScreenAction<TempomatModeCtrlTypChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_SETCONTROLMODE>, SwitchScreenAction<TempomatModeCtrlModChangeScreen>>,
makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<ModesSettingsMenu>, StaticMenuItemIcon<&icons::back>>
>
{};
}

Some files were not shown because too many files have changed in this diff Show More