415 lines
9.5 KiB
C++

/*
* Menu.cpp
*
* Created on: Jun 8, 2024
* Author: Carst
*/
#include <cstring>
#include <cstdio>
#include <cinttypes>
#include "Menu.hpp"
#include "Display.hpp"
#include "Button.hpp"
#include "Timer.hpp"
#include "ElektronischeLast.hpp"
#include "STM32G071KBT6.hpp"
namespace ElektronischeLast
{
static Timer timer_MainScreen = Timer();
static Timer timer_Backlight = Timer();
static Button ok = Button();
static Button up = Button();
static Button down = Button();
static Display lcd = Display();
static const uint8_t degreeSymbol[] = { 0x0E, 0x0A, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t arrowUp[] = { 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04 };
static const uint8_t arrowDown[] = { 0x04, 0x04, 0x04, 0x04, 0x04, 0x1F, 0x0E, 0x04 };
void Menu::init()
{
timer_MainScreen.start(500U);
timer_Backlight.start(3UL * 60UL * 1000UL);
ok.init(GPIOA, LL_GPIO_PIN_7);
up.init(GPIOA, LL_GPIO_PIN_9);
down.init(GPIOA, LL_GPIO_PIN_8);
lcd.init();
while(lcd.ready_for_data() == false)
{
lcd.run();
}
lcd.lcd_set_user_chars(Display::FirstSign, arrowUp);
while(lcd.ready_for_data() == false)
{
lcd.run();
}
lcd.lcd_set_user_chars(Display::ThirdSign, arrowDown);
while(lcd.ready_for_data() == false)
{
lcd.run();
}
lcd.lcd_set_user_chars(Display::SecondSign, degreeSymbol);
while(lcd.ready_for_data() == false)
{
lcd.run();
}
lcd.lcd_set_display(Display::eDispalyOn, Display::eCursorOff, Display::eCursorBlinkOff);
lcd.print(Display::Line1, "Elektronische Last");
up.cyclic();
down.cyclic();
if(up.isPressed() && down.isPressed())
{
menu_level = MenuLevel_Call;
}
}
void Menu::set_measurements(uint32_t spannung, uint32_t strom, uint32_t temperatur, uint32_t geschwindigkeit)
{
this->spannung = spannung;
this->strom = strom;
this->temperatur = temperatur;
this->geschwindigkeit = geschwindigkeit;
}
void Menu::run()
{
if(ok.cyclic())
{
timer_Backlight.restart();
lcd.set_backlight(true);
}
if(up.cyclic())
{
timer_Backlight.restart();
lcd.set_backlight(true);
}
if(down.cyclic())
{
timer_Backlight.restart();
lcd.set_backlight(true);
}
if(timer_Backlight.elapsed())
{
lcd.set_backlight(false);
this->menu_locked = true;
}
switch(menu_level)
{
case MenuLevel_Call:
menu_call();
break;
case MenuLevel_ICallInit:
menu_icall_init();
break;
case MenuLevel_ICall:
menu_icall();
break;
case MenuLevel_UCallInit:
menu_ucall_init();
break;
case MenuLevel_UCall:
menu_ucall();
break;
case MenuLevel_ISoll:
menu_isoll();
break;
case MenuLevel_Main:
default:
menu_main();
break;
}
lcd.run();
}
void Menu::menu_main(void)
{
if(timer_MainScreen.elapsed())
{
if(lcd.ready_for_data())
{
timer_MainScreen.start(500U);
char data[17U];
int32_t len = snprintf(data, sizeof(data) - 1, "%2" PRIu32 ".%02" PRIu32 "V",
spannung / 1000U, spannung % 1000U / 10U);
std::memset(&data[len], (int)' ', 16U - len);
snprintf(&data[12], sizeof(data) - 12, "%2" PRIu32 "%cC", temperatur, 0x1);
data[16] = '\0';
lcd.print(Display::Line1, data);
if(strom < 1000UL)
{
len = snprintf(data, sizeof(data) - 1, "%3" PRIu32 "mA", strom);
}
else
{
len = snprintf(data, sizeof(data) - 1, "%" PRIu32 ".%02" PRIu32 "A",
strom / 1000U, strom % 1000U / 10U);
}
std::memset(&data[len], (int)' ', 16U - len);
snprintf(&data[9], sizeof(data) - 9, "%4" PRIu32 "RPM", geschwindigkeit);
data[16] = '\0';
lcd.print(Display::Line2, data);
}
}
if(ok.isReleased())
{
if(this->menu_locked)
{
this->menu_locked = false;
}
else
{
this->menu_level = MenuLevel_ISoll;
this->configurations = 0UL;
}
}
if(up.isReleased() || down.isReleased())
{
this->menu_locked = false;
}
}
void Menu::menu_call(void)
{
if(lcd.ready_for_data())
{
switch(this->configurations)
{
case 0UL:
lcd.print(Display::Line1, "Kalibrierung: I");
lcd.print(Display::Line2, "Kalibrierung: U");
this->configurations++;
break;
case 1UL:
lcd.lcd_set_display(Display::eDispalyOn, Display::eCursorOn, Display::eCursorBlinkOn);
this->configurations++;
break;
case 2UL:
lcd.set_cursor(Display::Line1, 15U);
this->configurations++;
this->cursor = 1UL;
break;
default:
break;
}
}
if(ok.isReleased())
{
if(this->cursor == 1UL)
{
this->menu_level = MenuLevel_ICallInit;
}
else if(this->cursor == 2UL)
{
this->menu_level = MenuLevel_UCallInit;
}
this->configurations = 0UL;
}
else if(up.isReleased())
{
if(this->cursor == 1UL)
{
this->cursor = 2UL;
lcd.set_cursor(Display::Line2, 15U);
}
else if(this->cursor == 2UL)
{
this->cursor = 1UL;
lcd.set_cursor(Display::Line1, 15U);
}
}
else if(down.isReleased())
{
if(this->cursor == 1UL)
{
this->cursor = 2UL;
lcd.set_cursor(Display::Line2, 15U);
}
else if(this->cursor == 2UL)
{
this->cursor = 1UL;
lcd.set_cursor(Display::Line1, 15U);
}
}
}
void Menu::menu_icall_init(void)
{
char data[17U];
if(lcd.ready_for_data())
{
switch(this->configurations)
{
case 0UL:
set_new_sollstrom(1000UL);
soll = get_current_sollstrom();
snprintf(data, sizeof(data), "iSoll: %5" PRIu32 "mA", soll);
lcd.print(Display::Line1, "Stelle 1A ein ");
lcd.print(Display::Line2, data);
this->configurations++;
break;
case 1UL:
lcd.set_cursor(Display::Line2, 13UL);
this->configurations++;
break;
default:
break;
}
}
if(ok.isReleased())
{
this->menu_level = MenuLevel_ICall;
this->configurations = 0UL;
}
else if(down.isReleased())
{
soll--;
set_new_sollstrom(soll);
snprintf(data, sizeof(data), "iSoll: %5" PRIu32 "mA", soll);
lcd.print(Display::Line2, data);
this->configurations = 1UL;
}
else if(up.isReleased())
{
soll++;
set_new_sollstrom(soll);
snprintf(data, sizeof(data), "iSoll: %5" PRIu32 "mA", soll);
lcd.print(Display::Line2, data);
this->configurations = 1UL;
}
}
void Menu::menu_icall(void)
{
if(this->configurations == 0UL)
{
start_icall();
lcd.print(Display::Line1, "Kalibrierung... ");
lcd.print(Display::Line2, " ");
this->configurations++;
}
}
void Menu::menu_ucall_init(void)
{
if(this->configurations == 0UL)
{
set_new_sollstrom(0UL);
lcd.print(Display::Line1, "Lege 15V an ");
lcd.print(Display::Line2, " ");
this->configurations++;
}
if(ok.isReleased())
{
this->menu_level = MenuLevel_UCall;
this->configurations = 0UL;
}
}
void Menu::menu_ucall(void)
{
if(this->configurations == 0UL)
{
start_ucall();
lcd.print(Display::Line1, "Kalibrierung... ");
lcd.print(Display::Line2, " ");
this->configurations++;
}
}
void Menu::menu_isoll(void)
{
const char *header = "Sollstrom: ";
char data[17U];
int32_t len;
bool changed = false;
if(lcd.ready_for_data())
{
switch(this->configurations)
{
case 0UL:
cursor = 0U;
soll = get_current_sollstrom();
len = snprintf(data, sizeof(data) - 1, "%05" PRIu32 "mA", soll);
std::memset(&data[len], (int)' ', 16U - len);
data[16] = '\0';
lcd.print(Display::Line1, header);
lcd.print(Display::Line2, data);
this->configurations++;
break;
case 1UL:
lcd.lcd_set_display(Display::eDispalyOn, Display::eCursorOn, Display::eCursorBlinkOn);
this->configurations++;
break;
case 2UL:
lcd.set_cursor(Display::Line2, cursor);
this->configurations++;
break;
default:
if(ok.isReleased())
{
cursor++;
if(cursor > 3U)
{
menu_level = MenuLevel_Main;
set_new_sollstrom(soll);
lcd.lcd_set_display(Display::eDispalyOn, Display::eCursorOff, Display::eCursorBlinkOff);
}
else
{
lcd.set_cursor(Display::Line2, cursor);
}
}
else if(up.isReleased())
{
uint32_t step = 10000UL;
uint32_t i = 0U;
while(i < cursor)
{
step /= 10UL;
i++;
}
this->soll = (this->soll + step) % 11000UL;
changed = true;
}
else if(down.isReleased())
{
uint32_t step = 10000UL;
uint32_t i = 0U;
while(i < cursor)
{
step /= 10UL;
i++;
}
this->soll = (this->soll - step) % 11000UL;
changed = true;
}
if(changed)
{
len = snprintf(data, sizeof(data) - 1, "%05" PRIu32 "mA", this->soll);
std::memset(&data[len], (int)' ', 16U - len);
data[16] = '\0';
lcd.print(Display::Line2, data);
this->configurations = 2U;
}
break;
}
}
}
}