calib GUI WIP
This commit is contained in:
@@ -124,7 +124,6 @@ void switch_screen(screen_t pScreen, bool init) {
|
||||
s_app.initial_pushed = s_app.pushed;
|
||||
s_app.screen = pScreen;
|
||||
// clear the union field
|
||||
memset(&s_app.page, 0, sizeof(s_app.page));
|
||||
request_paint();
|
||||
|
||||
if (init) {
|
||||
|
||||
+17
-12
@@ -79,18 +79,23 @@ struct State {
|
||||
/// Pointer to the currently active screen func
|
||||
screen_t screen;
|
||||
|
||||
/// data specific for each of the screens (not persistent across screen switching)
|
||||
union {
|
||||
/// Generic menu
|
||||
struct menu_state {
|
||||
int pos;
|
||||
int len;
|
||||
uint32_t change_time;
|
||||
uint32_t slide_end_time;
|
||||
uint16_t text_slide;
|
||||
uint8_t tick_counter;
|
||||
} menu;
|
||||
} page;
|
||||
/// Generic menu
|
||||
struct menu_state {
|
||||
int pos;
|
||||
int len;
|
||||
uint32_t change_time;
|
||||
uint32_t slide_end_time;
|
||||
uint16_t text_slide;
|
||||
uint8_t tick_counter;
|
||||
} menu;
|
||||
|
||||
struct calib_state {
|
||||
int phase;
|
||||
float sample1;
|
||||
float sample2;
|
||||
int temp1;
|
||||
int temp2;
|
||||
} calib;
|
||||
};
|
||||
|
||||
extern struct State s_app;
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Created by MightyPork on 2023/04/09.
|
||||
//
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include "app_gui.h"
|
||||
#include "app_heater.h"
|
||||
#include "screen_menu.h"
|
||||
#include "ufb/fb_text.h"
|
||||
#include "app_temp.h"
|
||||
#include "snprintf.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
static const char* calib0_opts[] = {
|
||||
"Pokračovat",
|
||||
"Zrušit",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void calib0_cb(int opt) {
|
||||
switch (opt) {
|
||||
case 0:
|
||||
// Continue
|
||||
s_app.calib.phase++;
|
||||
request_paint();
|
||||
app_heater_manual_override(100);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch_screen(screen_home, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char* calib1_opts[] = {
|
||||
"Vzorek 1",
|
||||
"Zrušit",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void calib1_cb(int opt) {
|
||||
switch (opt) {
|
||||
case 0:
|
||||
// Continue
|
||||
s_app.calib.phase++;
|
||||
request_paint();
|
||||
s_app.calib.sample1 = app_temp_read_oven_raw();
|
||||
app_heater_manual_override(0);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
app_heater_manual_override(-1);
|
||||
switch_screen(screen_home, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* calib3_opts[] = {
|
||||
"Vzorek 2",
|
||||
"Zrušit",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void calib3_cb(int opt) {
|
||||
switch (opt) {
|
||||
case 0:
|
||||
// Continue
|
||||
s_app.calib.phase++;
|
||||
request_paint();
|
||||
s_app.calib.sample2 = app_temp_read_oven_raw();
|
||||
app_heater_manual_override(0);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
app_heater_manual_override(-1);
|
||||
switch_screen(screen_home, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void screen_manual_menu(GuiEvent event)
|
||||
{
|
||||
if (event == GUI_EVENT_SCREEN_INIT) {
|
||||
s_app.calib.phase = 0;
|
||||
s_app.calib.sample1 = s_app.calib.sample2 = 0.0f;
|
||||
s_app.calib.temp1 = s_app.calib.temp2 = 0;
|
||||
}
|
||||
|
||||
int phase = s_app.calib.phase;
|
||||
int *pT;
|
||||
switch (phase) {
|
||||
case 0:
|
||||
if (event == GUI_EVENT_PAINT) {
|
||||
fb_text(FBW/2, 14, "Vychlaďte", TEXT_CENTER, 1);
|
||||
fb_text(FBW/2, 24, "troubu", TEXT_CENTER, 1);
|
||||
}
|
||||
screen_menu(event, calib1_opts, calib1_cb);
|
||||
break;
|
||||
|
||||
case 1: // Heater is active, waiting for mark
|
||||
case 3:
|
||||
if (event == GUI_EVENT_PAINT) {
|
||||
fb_text(FBW/2, 14, "Zapiš teplotu", TEXT_CENTER, 1);
|
||||
}
|
||||
if (phase == 1) {
|
||||
screen_menu(event, calib1_opts, calib1_cb);
|
||||
} else {
|
||||
screen_menu(event, calib3_opts, calib3_cb);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 4:
|
||||
if (phase == 2) {
|
||||
pT = &s_app.calib.temp1;
|
||||
} else {
|
||||
pT = &s_app.calib.temp2;
|
||||
}
|
||||
|
||||
if (event == GUI_EVENT_PAINT) {
|
||||
fb_text(FBW/2, 14, phase == 2 ? "Teplota 1" : "Teplota 2", TEXT_CENTER, 1);
|
||||
SPRINTF(stmp, "%d°C", *pT);
|
||||
fb_text(FBW/2, 30, stmp, TEXT_CENTER | FONT_DOUBLE, 1);
|
||||
|
||||
fb_text(2, FBH - 8 * 3, "←→Nastav", 0, 1);
|
||||
fb_text(2, FBH - 8 * 2, "> Potvrdit", 0, 1);
|
||||
fb_text(2, FBH - 8 * 1, "» Zrušit", 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (push_time() > pdMS_TO_TICKS(500)) {
|
||||
input_sound_effect();
|
||||
app_heater_manual_override_clear();
|
||||
switch_screen(screen_home, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == GUI_EVENT_KNOB_PLUS) {
|
||||
if (*pT < 500) {
|
||||
*pT += 1;
|
||||
input_sound_effect();
|
||||
request_paint();
|
||||
}
|
||||
}
|
||||
else if (event == GUI_EVENT_KNOB_MINUS) {
|
||||
if (*pT > 0) {
|
||||
input_sound_effect();
|
||||
*pT -= 1;
|
||||
request_paint();
|
||||
}
|
||||
} else if (event == GUI_EVENT_KNOB_RELEASE) {
|
||||
s_app.calib.phase++;
|
||||
request_paint();
|
||||
|
||||
if (s_app.calib.phase == 5) {
|
||||
// TODO do the math
|
||||
PRINTF("Sample 1 %f, T1 %d\r\n", s_app.calib.sample1, s_app.calib.temp1);
|
||||
PRINTF("Sample 2 %f, T2 %d\r\n", s_app.calib.sample2, s_app.calib.temp2);
|
||||
|
||||
float corrected1 = c_to_val((float) s_app.calib.temp1);
|
||||
float corrected2 = c_to_val((float) s_app.calib.temp2);
|
||||
|
||||
float a = ;
|
||||
float b = ;
|
||||
|
||||
// TODO set and persist calibration
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (event == GUI_EVENT_PAINT) {
|
||||
fb_text(FBW/2, 14, "Hotovo", TEXT_CENTER, 1);
|
||||
fb_text(FBW/2, 36, "→Hlavní menu", TEXT_CENTER, 1);
|
||||
}
|
||||
if (event == GUI_EVENT_KNOB_RELEASE) {
|
||||
switch_screen(screen_home, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,8 @@ void screen_manual(GuiEvent event)
|
||||
{
|
||||
bool temp_changed = false;
|
||||
if (event == GUI_EVENT_SCREEN_INIT) {
|
||||
app_heater_manual_override_clear();
|
||||
app_heater_enable(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ void screen_menu(GuiEvent event, const char **options, menu_callback_t cb) {
|
||||
bool menu_changed = false;
|
||||
const uint32_t tickNow = xTaskGetTickCount();
|
||||
|
||||
struct menu_state *menu = &s_app.page.menu;
|
||||
struct menu_state *menu = &s_app.menu;
|
||||
|
||||
switch (event) {
|
||||
case GUI_EVENT_SCREEN_INIT:
|
||||
|
||||
+25
-5
@@ -39,12 +39,15 @@ static struct {
|
||||
float tuning_p;
|
||||
float tuning_i;
|
||||
float tuning_d;
|
||||
/// Manual PWM override (percent, -1 = override disable)
|
||||
int manual_override;
|
||||
// PID state
|
||||
struct PID pid;
|
||||
} state = {
|
||||
.tuning_p = 10.0f,
|
||||
.tuning_i = 0.052f,
|
||||
.tuning_d = 100.0f,
|
||||
.manual_override = -1,
|
||||
.pid = {
|
||||
.SampleTimeTicks = pdMS_TO_TICKS(1000),
|
||||
.outMax = 100.0f,
|
||||
@@ -62,6 +65,17 @@ static inline void heaterExitCritical() {
|
||||
osMutexRelease(heaterMutexHandle);
|
||||
}
|
||||
|
||||
void app_heater_manual_override(int percent) {
|
||||
heaterEnterCritical();
|
||||
PID_SetCtlMode(&state.pid, PID_MANUAL);
|
||||
state.manual_override = percent;
|
||||
heaterExitCritical();
|
||||
}
|
||||
|
||||
void app_heater_manual_override_clear() {
|
||||
app_heater_manual_override(-1);
|
||||
}
|
||||
|
||||
void app_heater_set_tuning(float p, float i, float d) {
|
||||
heaterEnterCritical();
|
||||
PID_SetTunings(&state.pid, p, i, d);
|
||||
@@ -127,13 +141,19 @@ void app_task_heater(void *argument)
|
||||
|
||||
heaterEnterCritical();
|
||||
app_safety_pass_reg_loop_running();
|
||||
PID_Compute(&state.pid, state.oven_temp);
|
||||
if (state.pid.ctlMode == PID_AUTOMATIC) {
|
||||
PRINTF("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output);
|
||||
|
||||
if (state.manual_override >= 0 && state.manual_override <= 100) {
|
||||
PRINTF("manual override %d%%\r\n", state.manual_override);
|
||||
heater_pwm_set_perc(state.pid.Output);
|
||||
} else {
|
||||
// turn it off
|
||||
heater_pwm_set_perc(0);
|
||||
PID_Compute(&state.pid, state.oven_temp);
|
||||
if (state.pid.ctlMode == PID_AUTOMATIC) {
|
||||
PRINTF("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output);
|
||||
heater_pwm_set_perc(state.pid.Output);
|
||||
} else {
|
||||
// turn it off
|
||||
heater_pwm_set_perc(0);
|
||||
}
|
||||
}
|
||||
heaterExitCritical();
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ extern osThreadId_t heaterTskHandle;
|
||||
|
||||
void app_task_heater(void *argument);
|
||||
|
||||
/// Clear manual override, disable heater for normal mode.
|
||||
void app_heater_manual_override_clear();
|
||||
|
||||
/// Set manual override PWM 0-100%.
|
||||
/// Also disables heater in the normal mode.
|
||||
void app_heater_manual_override(int percent);
|
||||
|
||||
/// Set heater regulator tuning.
|
||||
/// Mutex is locked internally.
|
||||
void app_heater_set_tuning(float p, float i, float d);
|
||||
|
||||
@@ -20,6 +20,9 @@ void app_temp_sample();
|
||||
/// The value is valid after calling app_temp_sample()
|
||||
float app_temp_read_oven();
|
||||
|
||||
/// Get the raw ADC value (divider voltage)
|
||||
float app_temp_read_oven_raw();
|
||||
|
||||
/// Read current SOC temperature (celsius)
|
||||
/// The value is valid after calling app_temp_sample()
|
||||
float app_temp_read_soc();
|
||||
|
||||
Reference in New Issue
Block a user