2020-06-01 21:45:36 +02:00
|
|
|
/* Reflow Oven Controller
|
|
|
|
*
|
|
|
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
|
|
|
*
|
|
|
|
* This file is part of the Reflow Oven Controller Project.
|
|
|
|
*
|
|
|
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with the reflow oven controller project.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2020-06-13 22:47:45 +02:00
|
|
|
#include <reflow-controller/reflow-menu.h>
|
2020-06-09 22:50:20 +02:00
|
|
|
#include <reflow-controller/ui/menu.h>
|
|
|
|
#include <reflow-controller/ui/lcd.h>
|
2020-06-12 01:35:37 +02:00
|
|
|
#include <reflow-controller/rotary-encoder.h>
|
|
|
|
#include <reflow-controller/systick.h>
|
|
|
|
#include <reflow-controller/adc-meas.h>
|
|
|
|
#include <reflow-controller/safety-adc.h>
|
2020-06-13 22:47:45 +02:00
|
|
|
#include <reflow-controller/temp-converter.h>
|
|
|
|
#include <helper-macros/helper-macros.h>
|
2020-06-14 16:19:42 +02:00
|
|
|
#include <stm-periph/unique-id.h>
|
2020-06-12 01:35:37 +02:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
2020-06-13 22:47:45 +02:00
|
|
|
#include <string.h>
|
2020-06-14 13:25:47 +02:00
|
|
|
#include <inttypes.h>
|
2020-06-09 22:50:20 +02:00
|
|
|
|
2020-06-09 22:53:13 +02:00
|
|
|
static char __attribute__((section(".ccmram"))) display_buffer[4][21] = {0};
|
2020-06-12 01:35:37 +02:00
|
|
|
static struct lcd_menu reflow_menu;
|
2020-06-14 14:50:27 +02:00
|
|
|
static struct lcd_menu * const reflow_menu_ptr = &reflow_menu;
|
2020-06-09 22:50:20 +02:00
|
|
|
|
|
|
|
static void update_display_buffer(uint8_t row, const char *data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (row > 4)
|
|
|
|
return;
|
|
|
|
if (!data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; data[i] && i < LCD_CHAR_WIDTH; i++) {
|
|
|
|
display_buffer[row][i] = data[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
display_buffer[row][i] = 0;
|
|
|
|
}
|
|
|
|
|
2020-06-12 01:35:37 +02:00
|
|
|
static void reflow_menu_monitor(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
|
|
|
|
{
|
|
|
|
static void *my_parent;
|
|
|
|
static uint64_t my_timestamp = 0;
|
|
|
|
char line[17];
|
|
|
|
float tmp;
|
|
|
|
int res;
|
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
|
|
|
|
my_parent = parent;
|
|
|
|
menu_display_clear(menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (systick_ticks_have_passed(my_timestamp, 250)) {
|
2020-06-13 22:47:45 +02:00
|
|
|
my_timestamp = systick_get_global_tick();
|
2020-06-12 01:35:37 +02:00
|
|
|
adc_pt1000_get_current_resistance(&tmp);
|
|
|
|
snprintf(line, sizeof(line), "Res: %.1f", tmp);
|
|
|
|
menu->update_display(0, line);
|
|
|
|
|
|
|
|
res = temp_converter_convert_resistance_to_temp(tmp, &tmp);
|
|
|
|
switch (res) {
|
|
|
|
case -1:
|
|
|
|
prefix = "<";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
prefix = ">";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
prefix = "";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(line, sizeof(line), "Temp: %s%.1f " LCD_DEGREE_SYMBOL_STRING "C", prefix, tmp);
|
|
|
|
menu->update_display(1, line);
|
|
|
|
|
|
|
|
tmp = safety_adc_get_temp();
|
|
|
|
snprintf(line, sizeof(line), "Tj: %.1f " LCD_DEGREE_SYMBOL_STRING "C", tmp);
|
|
|
|
menu->update_display(2, line);
|
|
|
|
|
|
|
|
tmp = safety_adc_get_vref();
|
|
|
|
snprintf(line, sizeof(line), "Vref: %.1f mV", tmp);
|
|
|
|
menu->update_display(3, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (menu->inputs.push_button == BUTTON_SHORT_RELEASED || menu->inputs.push_button == BUTTON_LONG) {
|
|
|
|
menu_entry_dropback(menu, my_parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-13 22:47:45 +02:00
|
|
|
static void reflow_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
|
|
|
|
{
|
|
|
|
static void *my_parent;
|
|
|
|
static bool button_ready;
|
2020-06-14 13:25:47 +02:00
|
|
|
static int page = 0;
|
2020-06-14 14:16:12 +02:00
|
|
|
static uint32_t uptime_secs;
|
|
|
|
uint32_t new_uptime_secs;
|
|
|
|
uint32_t uptime_mins;
|
|
|
|
uint32_t uptime_hours;
|
|
|
|
uint32_t uptime_days;
|
2020-06-14 13:25:47 +02:00
|
|
|
int16_t rot_delta;
|
2020-06-14 16:19:42 +02:00
|
|
|
uint32_t ser1, ser2, ser3;
|
2020-06-14 13:25:47 +02:00
|
|
|
enum button_state push_button;
|
2020-06-13 22:47:45 +02:00
|
|
|
|
|
|
|
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
|
2020-06-14 13:25:47 +02:00
|
|
|
uptime_secs = 0ULL;
|
|
|
|
page = 0;
|
2020-06-13 22:47:45 +02:00
|
|
|
my_parent = parent;
|
|
|
|
button_ready = false;
|
|
|
|
menu_display_clear(menu);
|
2020-06-14 13:25:47 +02:00
|
|
|
menu_ack_rotary_delta(menu);
|
2020-06-14 14:45:58 +02:00
|
|
|
}
|
2020-06-14 13:25:47 +02:00
|
|
|
|
2020-06-14 16:26:32 +02:00
|
|
|
rot_delta = menu_get_rotary_delta(menu);
|
|
|
|
if (rot_delta >= 4) {
|
|
|
|
menu_ack_rotary_delta(menu);
|
|
|
|
if (page < 4) {
|
|
|
|
page++;
|
|
|
|
menu_display_clear(menu);
|
|
|
|
}
|
|
|
|
} else if (rot_delta <= -4) {
|
|
|
|
menu_ack_rotary_delta(menu);
|
|
|
|
if (page > 0) {
|
|
|
|
page--;
|
|
|
|
menu_display_clear(menu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-14 13:25:47 +02:00
|
|
|
switch (page) {
|
|
|
|
case 0:
|
|
|
|
menu_lcd_output(menu, 0, LCD_SHIMATTA_STRING " Shimatta");
|
|
|
|
menu_lcd_output(menu, 1, "Oven Controller");
|
|
|
|
menu_lcd_output(menu, 2, "(c) Mario H\xF5ttel");
|
2020-06-14 16:19:42 +02:00
|
|
|
menu_lcd_output(menu, 3, "Page 1/5");
|
2020-06-14 13:25:47 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
menu_lcd_output(menu, 0, "Version Number:");
|
2020-06-14 14:45:58 +02:00
|
|
|
menu_lcd_outputf(menu, 1, "%.*s", LCD_CHAR_WIDTH, xstr(GIT_VER));
|
2020-06-14 13:25:47 +02:00
|
|
|
if (strlen(xstr(GIT_VER)) > LCD_CHAR_WIDTH) {
|
2020-06-14 14:45:58 +02:00
|
|
|
menu_lcd_outputf(menu, 2, "%s", &xstr(GIT_VER)[LCD_CHAR_WIDTH]);
|
2020-06-14 13:25:47 +02:00
|
|
|
}
|
2020-06-15 22:00:47 +02:00
|
|
|
#ifdef DEBUGBUILD
|
|
|
|
menu_lcd_output(menu, 3, "Page 2/5 [DEBUG]");
|
|
|
|
#else
|
2020-06-14 16:19:42 +02:00
|
|
|
menu_lcd_output(menu, 3, "Page 2/5");
|
2020-06-15 22:00:47 +02:00
|
|
|
#endif
|
2020-06-14 13:25:47 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-06-14 16:19:42 +02:00
|
|
|
menu_lcd_output(menu, 0, "Compile Info");
|
|
|
|
menu_lcd_output(menu, 1, __DATE__);
|
|
|
|
menu_lcd_output(menu, 2, __TIME__);
|
|
|
|
menu_lcd_output(menu, 3, "Page 3/5");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
unique_id_get(&ser1, &ser2, &ser3);
|
|
|
|
|
|
|
|
menu_lcd_outputf(menu, 0, "Serial: %08X", ser1);
|
|
|
|
menu_lcd_outputf(menu, 1, " %08X", ser2);
|
|
|
|
menu_lcd_outputf(menu, 2, " %08X", ser3);
|
|
|
|
menu_lcd_output(menu, 3, "Page 4/5");
|
|
|
|
break;
|
|
|
|
case 4:
|
2020-06-14 14:16:12 +02:00
|
|
|
systick_get_uptime_from_tick(&uptime_days, &uptime_hours, &uptime_mins, &new_uptime_secs);
|
2020-06-14 13:25:47 +02:00
|
|
|
if (new_uptime_secs != uptime_secs) {
|
|
|
|
uptime_secs = new_uptime_secs;
|
|
|
|
menu_lcd_output(menu, 0, "Uptime:");
|
2020-06-14 16:19:42 +02:00
|
|
|
menu_lcd_outputf(menu, 1, "%lu day%s %02lu:%02lu:%02lu",
|
|
|
|
uptime_days, (uptime_days == 1 ? "" : "s"), uptime_hours, uptime_mins, uptime_secs);
|
|
|
|
menu_lcd_output(menu, 3, "Page 5/5");
|
2020-06-14 13:25:47 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
page = 0;
|
|
|
|
break;
|
2020-06-13 22:47:45 +02:00
|
|
|
}
|
|
|
|
|
2020-06-14 13:25:47 +02:00
|
|
|
push_button = menu_get_button_state(menu);
|
|
|
|
|
|
|
|
if (push_button == BUTTON_IDLE)
|
2020-06-13 22:47:45 +02:00
|
|
|
button_ready = true;
|
|
|
|
|
|
|
|
if (button_ready &&
|
2020-06-14 13:25:47 +02:00
|
|
|
(push_button == BUTTON_SHORT_RELEASED || push_button == BUTTON_LONG)) {
|
2020-06-13 22:47:45 +02:00
|
|
|
menu_entry_dropback(menu, my_parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-12 01:35:37 +02:00
|
|
|
static void reflow_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
|
|
|
|
{
|
|
|
|
(void)parent;
|
|
|
|
static struct menu_list list;
|
|
|
|
static bool button_valid;
|
2020-06-13 22:47:45 +02:00
|
|
|
static const char * const root_entry_names[] = {
|
|
|
|
"About",
|
|
|
|
"Monitoring",
|
2020-06-12 01:35:37 +02:00
|
|
|
NULL
|
|
|
|
};
|
2020-06-13 22:47:45 +02:00
|
|
|
static const menu_func_t root_entry_funcs[] = {
|
|
|
|
reflow_menu_about,
|
|
|
|
reflow_menu_monitor
|
|
|
|
};
|
2020-06-14 13:25:47 +02:00
|
|
|
enum button_state push_button;
|
|
|
|
int16_t rot_delta;
|
2020-06-13 22:47:45 +02:00
|
|
|
|
2020-06-12 01:35:37 +02:00
|
|
|
if (entry_type != MENU_ENTRY_CONTINUE) {
|
|
|
|
menu_display_clear(menu);
|
|
|
|
update_display_buffer(0, "Main Menu");
|
2020-06-14 01:04:21 +02:00
|
|
|
menu_ack_rotary_delta(menu);
|
2020-06-13 22:47:45 +02:00
|
|
|
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
|
|
|
|
button_valid = false;
|
|
|
|
list.entry_names = root_entry_names;
|
|
|
|
list.submenu_list = root_entry_funcs;
|
|
|
|
list.update_display = menu->update_display;
|
|
|
|
list.currently_selected = 0;
|
|
|
|
menu_list_compute_count(&list);
|
|
|
|
}
|
2020-06-12 01:35:37 +02:00
|
|
|
}
|
|
|
|
|
2020-06-14 13:25:47 +02:00
|
|
|
push_button = menu_get_button_state(menu);
|
|
|
|
rot_delta = menu_get_rotary_delta(menu);
|
|
|
|
|
|
|
|
if (push_button == BUTTON_IDLE) {
|
2020-06-12 01:35:37 +02:00
|
|
|
button_valid = true;
|
2020-06-14 13:25:47 +02:00
|
|
|
} else if (button_valid && push_button == BUTTON_SHORT_RELEASED) {
|
2020-06-13 22:47:45 +02:00
|
|
|
/* Enter currently selected menu_entry */
|
|
|
|
menu_list_enter_selected_entry(&list, menu);
|
2020-06-12 01:35:37 +02:00
|
|
|
}
|
|
|
|
|
2020-06-14 13:25:47 +02:00
|
|
|
if (rot_delta >= 4) {
|
2020-06-12 01:35:37 +02:00
|
|
|
menu_list_scroll_down(&list);
|
|
|
|
menu_ack_rotary_delta(menu);
|
2020-06-14 13:25:47 +02:00
|
|
|
} else if (rot_delta <= -4) {
|
2020-06-12 01:35:37 +02:00
|
|
|
menu_list_scroll_up(&list);
|
|
|
|
menu_ack_rotary_delta(menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
menu_list_display(&list, 1, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
int reflow_menu_handle()
|
|
|
|
{
|
|
|
|
int32_t rot_delta;
|
|
|
|
enum button_state button;
|
|
|
|
static enum lcd_fsm_ret lcd_ret = LCD_FSM_NOP;
|
|
|
|
|
|
|
|
rot_delta = rotary_encoder_get_change_val();
|
|
|
|
button = button_read_event();
|
|
|
|
|
|
|
|
menu_handle(reflow_menu_ptr, (int16_t)rot_delta, button);
|
|
|
|
|
2020-06-14 17:52:27 +02:00
|
|
|
if (lcd_ret == LCD_FSM_CALL_AGAIN || lcd_tick_100us >= 5) {
|
2020-06-12 01:35:37 +02:00
|
|
|
lcd_ret = lcd_fsm_write_buffer(display_buffer);
|
2020-06-14 13:25:47 +02:00
|
|
|
lcd_tick_100us = 0UL;
|
2020-06-13 22:47:45 +02:00
|
|
|
}
|
2020-06-12 01:35:37 +02:00
|
|
|
|
2020-06-14 01:34:42 +02:00
|
|
|
if (lcd_ret == LCD_FSM_CALL_AGAIN)
|
2020-06-12 01:35:37 +02:00
|
|
|
return 0;
|
2020-06-14 01:34:42 +02:00
|
|
|
else
|
|
|
|
return 1;
|
2020-06-12 01:35:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void reflow_menu_init()
|
|
|
|
{
|
|
|
|
rotary_encoder_setup();
|
|
|
|
button_init();
|
|
|
|
lcd_init();
|
|
|
|
|
|
|
|
menu_init(reflow_menu_ptr, reflow_menu_root_entry, update_display_buffer);
|
|
|
|
}
|