Below is the file 'menu.c' from this revision. You can also download the file.

/* menu.c */

//#include <stdio.h>

#include <stddef.h>
#include <string.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/atomic.h>

#include "common.h"
#include "menu.h"
#include "display.h"
#include "timer.h"
#include "therm.h"
#include "config.h"
#include "beep.h"
#include "fields.h"
#include "profile.h"
#include "control.h"

uint8_t menu_current;
uint8_t menu_row;
uint8_t field_row;
uint8_t menu_next;
uint8_t menu_redraw;
bool edit_dirty;

#define REDRAW_NONE 0
#define REDRAW_FIELDS 1
#define REDRAW_ALL 2

uint8_t run_status;

bool menu_editing;
uint8_t menu_editing_field;

menu_t *menu_current_p;

const char str_b[] PROGMEM = "B";
const char str_e[] PROGMEM = "E";
const char str_j[] PROGMEM = "J";
const char str_k[] PROGMEM = "K";
const char str_n[] PROGMEM = "N";
const char str_r[] PROGMEM = "R";
const char str_s[] PROGMEM = "S";
const char str_t[] PROGMEM = "T";

PGM_P const enum_thermocouple_types[] PROGMEM = {
    str_b,
    str_e,
    str_j,
    str_k,
    str_n,
    str_r,
    str_s,
    str_t
};

const char str_negative[] PROGMEM = "-";
const char str_positive[] PROGMEM = "+";

PGM_P const enum_posneg[] PROGMEM = {
    str_negative,
    str_positive
};

const char str_off[] PROGMEM = "Off";
const char str_on[]  PROGMEM = "On";

PGM_P const enum_boolean[] PROGMEM = {
    str_off,
    str_on
};

const char str_50hz[] PROGMEM = "50Hz";
const char str_60hz[] PROGMEM = "60Hz";

PGM_P const enum_frequency[] PROGMEM = {
    str_50hz,
    str_60hz
};

const char str_degc[]  PROGMEM = "\047C";
const char str_degf[]  PROGMEM = "\047F";
/* str_k already defined */
const char str_degde[] PROGMEM = "\047De";
const char str_degn[]  PROGMEM = "\047N";
const char str_degr[]  PROGMEM = "\047R";
const char str_degre[] PROGMEM = "\047Re";
const char str_degro[] PROGMEM = "\047Ro";
const char str_mev[]   PROGMEM = "meV";

#define TEMPERATURE_CELSIUS 0
#define TEMPERATURE_FAHRENHEIT 1
#define TEMPERATURE_KELVIN 2
#define TEMPERATURE_DELISLE 3
#define TEMPERATURE_NEWTON 4
#define TEMPERATURE_RANKINE 5
#define TEMPERATURE_REAUMUR 6
#define TEMPERATURE_ROMER 7
#define TEMPERATURE_MEV 8

PGM_P const enum_units[] PROGMEM = {
    str_degc,
    str_degf,
    str_k,
    str_degde,
    str_degn,
    str_degr,
    str_degre,
    str_degro,
    str_mev
};

const char str_seconds[] PROGMEM = "s";
const char str_minutes[] PROGMEM = "m";
const char str_hours[] PROGMEM = "h";

PGM_P const enum_time_units[] PROGMEM = {
    str_seconds,
    str_minutes,
    str_hours
};

const char str_0[]   PROGMEM = "0";
const char str_1[]   PROGMEM = "1";
const char str_2[]   PROGMEM = "2";
const char str_3[]   PROGMEM = "3";
const char str_4[]   PROGMEM = "4";
const char str_5[]   PROGMEM = "5";
const char str_6[]   PROGMEM = "6";
const char str_7[]   PROGMEM = "7";
const char str_8[]   PROGMEM = "8";
const char str_9[]   PROGMEM = "9";

PGM_P const enum_digits[] PROGMEM = {
    str_0,
    str_1,
    str_2,
    str_3,
    str_4,
    str_5,
    str_6,
    str_7,
    str_8,
    str_9,
};

const char str_start[]     PROGMEM = "Start?";
const char str_running[]   PROGMEM = "Run";
const char str_finished[]  PROGMEM = "Done";
//const char str_error[]     PROGMEM = "Error";

PGM_P const enum_status[] PROGMEM = {
    str_start,
    str_running,
    str_finished
//    str_error
};

#define RUN_STATUS_READY 0
#define RUN_STATUS_RUNNING 1
#define RUN_STATUS_FINISHED 2
#define RUN_STATUS_ERROR 3

const char str_empty[]     PROGMEM = "";
const char str_fault[]     PROGMEM = "FAULT";
//const char str_open[]      PROGMEM = "Connect thermocouple";
//const char str_chiprange[] PROGMEM = "Cold junction range";
//const char str_temprange[] PROGMEM = "Thermocouple range";

PGM_P const enum_faultstatus[] PROGMEM = {
    str_empty,
    str_fault
//    str_open,
//    str_chiprange,
//    str_temprange
};

const char str_run_profile[]  PROGMEM = "Run profile";
const char str_edit_profile[] PROGMEM = "Edit profile";
const char str_configure[]    PROGMEM = "Configure";
const char str_faultstatus[]  PROGMEM = "\x0a";
const char str_oven[]         PROGMEM = "Oven       \x08\x02\x02\x02\x02.\x02\x04\x04\x04";
const char str_ambient[]      PROGMEM = "Ambient    \x08\x02\x02\x02\x02.\x02\x04\x04\x04";

PGM_P const menu_main[] PROGMEM = {
    str_run_profile,
    str_edit_profile,
    str_configure,
    NULL,
    str_faultstatus,
    NULL,
    str_oven,
    str_ambient
};

const char str_placeholder[] PROGMEM = "Placeholder";
const char str_selecting_profile[]      PROGMEM = "Selecting profile";
const char str_str[]      PROGMEM = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01";
const char str_editstr[]      PROGMEM = "\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11";

PGM_P const menu_select_profile[] PROGMEM = {
    str_str,
    str_str,
    str_str,
    str_str,
    str_str,
    str_str,
    str_str,
    str_str
};

const char str_editing_profile[]      PROGMEM = "Editing profile";
const char str_name_field[]      PROGMEM = "> Name field <";
const char str_start_temperature[]      PROGMEM = "Start temp   \x18\x12\x12\x12\x12\x04<<";
const char str_edit_field[] PROGMEM = "\x02\x02.\x02\x02/ \x12\x12\x12\x12\x13 \x18\x12\x12\x12\x12\x04<<";

PGM_P const menu_edit_profile[] PROGMEM = {
    str_editstr,
    str_start_temperature,
    str_edit_field,
    str_edit_field,
    str_edit_field,
    str_edit_field,
    str_edit_field,
    str_edit_field,
};

const char str_contrast[]      PROGMEM = "Contrast          \x12\x12\x12";
const char str_beep[]          PROGMEM = "Beep              \x15>>";
const char str_thermocouple[]  PROGMEM = "Thermocouple        \x16";
const char str_frequency[]     PROGMEM = "Frequency        \x17>>>";
const char str_units[]         PROGMEM = "Units             \x14>>";
const char str_p[]             PROGMEM = "P               \x18\x12.\x12\x12";
const char str_i[]             PROGMEM = "I               \x18\x12.\x12\x12";
const char str_d[]             PROGMEM = "D               \x18\x12.\x12\x12";

PGM_P const menu_configuration[] PROGMEM = {
    str_contrast,
    str_beep,
    str_thermocouple,
    str_frequency,
    str_units,
    str_p,
    str_i,
    str_d
};

const char str_running_profile[]      PROGMEM = "\x09\x09\x09\x09\x09\x09\x12\x12\x12\x12\x13\x08\x02\x02\x02\x02.\x02\x04<<";

PGM_P const menu_run_profile[] PROGMEM = {
    str_running_profile,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

static void main_menu_fields(uint8_t row);
static void configuration_fields(uint8_t row);
static void save_configuration_fields(uint8_t row);
static void select_profile_fields(uint8_t row);
static void edit_profile_fields(uint8_t row);
static void save_profile_fields(uint8_t row);
static void update_run_status(uint8_t row);

menu_t menus[] = {
    { menu_main, 0, 2, main_menu_fields, NULL },
    { menu_select_profile, 0, 7, select_profile_fields, NULL },
    { menu_configuration, 0, 7, configuration_fields, save_configuration_fields },
    { menu_edit_profile, 0, 7, edit_profile_fields, save_profile_fields },
    { menu_run_profile, 7, 7, update_run_status, NULL }
};

#define TEMPERATURE_UNIT 0x1000L

int8_t temp_n[] = {1, 9, 1, -3, 33, 9, 4, 21, 10};
int8_t temp_d[] = {1, 5, 1, 2, 100, 5, 5, 40, 116};
int32_t temp_off[] = {0, 32*TEMPERATURE_UNIT, 1118822, -614400, 0, 2013880, 0, 30720, 96450};

int32_t temperature_from_kelvin(temp_t temp)
{
    uint8_t units = config.units;
    int32_t temp32 = temp;
    int32_t source = ((temp32-2732)<<12) / 10;
    int32_t result;
    result = source * temp_n[units] / temp_d[units] + temp_off[units];
//    printf("temp = %d, source = %d (%x), result = %d (%x)\n", temp, source, source, result, result);
    return result;
}

temp_t temperature_to_kelvin(int32_t source)
{
    uint8_t units = config.units;
    int32_t result = (source - temp_off[units]) * temp_d[units] / temp_n[units];

    return therm_reduce(result);
}

static void update_run_status(uint8_t row)
{
    temp_t temp = therm_temp();
    write_field_enum(0, run_status);
    write_field_uint16(1, control_now());
    write_field_enum(2, 0);
    write_field_temperature(3, TRUE, temp);
}

static void main_menu_fields(uint8_t row)
{
    temp_t temp;

    switch (row) {
    case 4:
	write_field_enum(0, therm_fault()?1:0);
	return;
    case 6:
	temp = therm_temp();
	break;
    case 7:
	temp = therm_coldtemp();
	break;
    default:
	return;
    }

    write_field_temperature(0, TRUE, temp);
}

static void configuration_fields(uint8_t row)
{
    if (row == 0) {
	write_field_uint8(0, config.contrast);
	return;
    }

    if (row > 4) {
	int16_t value16;
	int32_t val;
	switch (row) {
	case 5:
	    value16 = config.p;
	    break;
	case 6:
	    value16 = config.i;
	    break;
	case 7:
	    value16 = config.d;
	    break;
	default:
	    return;
	}
	val = (int32_t)value16 << 5;
	write_field_fracint(0, TRUE, TRUE, val);
    } else {
	uint8_t value8;
	switch (row) {
	case 1:
	    value8 = config.beep;
	    break;
	case 2:
	    value8 = config.thermocouple_type;
	    break;
	case 3:
	    value8 = config.frequency;
	    break;
	case 4:
	    value8 = config.units;
	    break;
	}
	write_field_enum(0, value8);
    }
}

static void save_configuration_fields(uint8_t row)
{
    if (row == 0) {
	config.contrast = read_field_uint8(0);
	return;
    }

    if (row > 4) {
	int16_t value16 = read_field_fracint(0, TRUE) >> 5;
	switch (row) {
	case 5:
	    config.p = value16;
	    break;
	case 6:
	    config.i = value16;
	    break;
	case 7:
	    config.d = value16;
	    break;
	}
    } else {
	uint8_t value8 = read_field_enum(0);
	switch (row) {
	case 1: 
	    config.beep = value8;
	    break;
	case 2: 
	    config.thermocouple_type = value8;
	    break;
	case 3: 
	    config.frequency = value8;
	    break;
	case 4: 
	    config.units = value8;
	    break;
	}
    }
}

static void select_profile_fields(uint8_t row)
{
    profile_select(row);
    memcpy(field_values, &profile_p->name, PROFILE_NAME_LENGTH);
}

static void save_profile_fields(uint8_t row)
{
    int32_t temp;
    temp_t k_temp;
    uint8_t n;

    if (row == 0) {
	memcpy(profile_p->name, field_values, PROFILE_NAME_LENGTH);
	return;
    }

    n = find_field_number(find_editable_field(0, FALSE));

    temp = read_field_fracint(n+((row == 1)?0:2), FALSE);

    k_temp = temperature_to_kelvin(temp);
    set_profile_temperature(k_temp);

    if (row == 1)
	return;

    set_profile_time(row-2, read_field_uint16(n), read_field_enum(n+1));
}

static void edit_profile_fields(uint8_t row)
{
    int32_t unit_temp, prev_temp, step;
    temp_t temp;
    uint16_t time;
    uint8_t time_units;
    if (row == 0) {
	memcpy(field_values, profile_p->name, PROFILE_NAME_LENGTH);
	return;
    }

    temp = get_profile_temperature(row);
    write_field_temperature(((row == 1)?0:4), FALSE, temp);
    if (row == 1)
	return;

    unit_temp = temperature_from_kelvin(temp);
    prev_temp = temperature_from_kelvin(get_profile_temperature(row-1));

    time = profile_get_time(row-2);
    time_units = profile_get_time_units(row-2);

    if (time == 0)
	step = 0;
    else
	step = (unit_temp - prev_temp) / time;

    write_field_fracint(0, FALSE, TRUE, step);
    write_field_uint16(2, time);
    write_field_enum(3, time_units);
}

#define MENU_MAIN 0
#define MENU_SELECT_PROFILE 1
#define MENU_CONFIGURATION 2
#define MENU_EDIT_PROFILE 3
#define MENU_RUN_PROFILE 4

char menu_getchar(uint8_t col)
{
    PGM_P ptr = get_string(&menu_current_p->text[field_row]);

    if (!ptr)
	return '\0';

    if (col > 20)
	return '\0';

    return pgm_read_byte(ptr + col);
}

field_t fields[] = {
    {NULL /* ASCII */, 127-32, 1},
    {enum_digits, ARRAY_SIZE(enum_digits), 1},
    {enum_time_units, ARRAY_SIZE(enum_time_units), 1},
    {enum_units, ARRAY_SIZE(enum_units), 3},
    {enum_boolean, ARRAY_SIZE(enum_boolean), 3},
    {enum_thermocouple_types, ARRAY_SIZE(enum_thermocouple_types), 1},
    {enum_frequency, ARRAY_SIZE(enum_frequency), 4},
    {enum_posneg, ARRAY_SIZE(enum_posneg), 1},
    {enum_status, ARRAY_SIZE(enum_status), 6},
    {enum_faultstatus, ARRAY_SIZE(enum_faultstatus), 21}
};

static void display_field(char c, uint8_t col)
{
    uint8_t i;

    if (field_is_text(c)) {
	if ((field_values[col] >= 32) && (field_values[col] < 32+field_display_entries(c)))
	    display_putchar(field_values[col]);
	else
	    display_putchar('?');
	return;
    }

    if (field_values[col] >= field_display_entries(c)) {
	for (i = 0; i < field_length(c); i++)
	    display_putchar('?');
    } else {
	PGM_P str = field_text(c, field_values[col]);
	i = 0;
	if (field_length(c) > 1) {
	    i = field_length(c) - strlen_P(str);
	    if (menu_getchar(col+1) == '>')
		for (; i; i--)
		    display_putchar(' ');
	}
	display_putstr_P(str);
	for (; i; i--)
	    display_putchar(' ');
    }
}

#define menu_draw_current_row() menu_draw_row(menu_row)

static void menu_set_fields(uint8_t row)
{
    menu_t *menu = menu_current_p;
    field_row = row;
    if ((!menu_editing) && menu->get_field)
	menu->get_field(row);
}

static void menu_draw_row(uint8_t row)
{
    uint8_t col;
    display_settextpos(0, row);
    display_setinverse((row == menu_row) && !menu_editing);
    if (get_string(&menu_current_p->text[row])) {
	char c;
	menu_set_fields(row);
	col = 0;
	while ((c = menu_getchar(col)) != '\0') {
	    if (menu_editing)
		display_setinverse(col == menu_editing_field);
	    if (is_field(c)) {
		display_field(c, col);
		col += field_length(c);
	    } else {
		display_putchar(c);
		col++;
	    }
	}
    }
    display_clearline();
}

#if 1
static void display_menu(bool all)
{
    uint8_t row;

    for (row = 0; row < 8; row++) {
	field_row = row;
	if (all || (find_field(0) != 255))
	    menu_draw_row(row);
    }
}
#endif

void set_menu(uint8_t new_menu)
{
    if (new_menu == menu_current)
	return;
    menu_current = new_menu;
    menu_current_p = &menus[new_menu];
    menu_redraw = TRUE;
//    memcpy_P(&menu_row, &menu_current_p->first_line, sizeof(menu_row));
    menu_row = 0;
    menu_editing = FALSE;
}

void menu_init(void)
{
    /* Make sure set_menu does its work */
    menu_current = MENU_MAIN+1;
    set_menu(MENU_MAIN);
    display_init();
}

#define BUTTON_UP 1
#define BUTTON_DOWN 2
#define BUTTON_LEFT 4
#define BUTTON_RIGHT 3

static void menu_end_edit(void)
{
    menu_t *menu = menu_current_p;
    menu_editing = FALSE;
    if (menu->put_field)
	menu->put_field(menu_row);
    menu_redraw = TRUE;
}

static void menu_edit_new_field(uint8_t field, bool left)
{
    field = find_editable_field(field, left);
    menu_editing_field = field;
    menu_editing = TRUE;
    edit_dirty = FALSE;
    if (field == 255)
	menu_end_edit();
    menu_draw_row(menu_row);
}

static void increment_value(int8_t inc)
{
    uint8_t val = field_values[menu_editing_field];
    uint8_t c = menu_getchar(menu_editing_field);

    uint8_t min = 0;
    uint8_t max = field_display_entries(c) - 1;

    if (field_is_text(c)) {
	min += 32;
	max += 32;
    }

    if (inc < 0 && val == min)
	val = max;
    else if (inc > 0 && val == max)
	val = min;
    else
	val += inc;

    field_values[menu_editing_field] = val;
    edit_dirty = TRUE;
}

static void menu_navigate_up(void)
{
    if (menu_row == menu_current_p->first_line)
       return;

    menu_row--;
    menu_draw_row(menu_row+1);
    menu_draw_row(menu_row);
}

static void menu_navigate_down(void)
{
    if (menu_row == menu_current_p->last_line)
       return;

    menu_row++;
    menu_draw_row(menu_row-1);
    menu_draw_row(menu_row);
}

static void menu_navigate_into(void)
{
    uint8_t menu = menu_current;
    switch (menu) {
    case MENU_MAIN:
	switch (menu_row) {
	case 0:
	    menu = MENU_SELECT_PROFILE;
	    menu_next = MENU_RUN_PROFILE;
	    break;
	case 1:
	    menu = MENU_SELECT_PROFILE;
	    menu_next = MENU_EDIT_PROFILE;
	    break;
	case 2:
	    menu = MENU_CONFIGURATION;
	    break;
	}
	break;

    case MENU_SELECT_PROFILE:
	menu = menu_next;
	profile_select(menu_row);
	break;

    case MENU_RUN_PROFILE:
	control_start();
	run_status = RUN_STATUS_RUNNING;
	break;

    default:
	menu_edit_new_field(21, TRUE);
	break;
    }

    set_menu(menu);
}

static void menu_navigate_back(void)
{
    uint8_t menu = menu_current;
    switch (menu) {
    case MENU_EDIT_PROFILE:
	profile_save();
    case MENU_RUN_PROFILE:
	menu = MENU_SELECT_PROFILE;
	break;
    default:
	menu = MENU_MAIN;
	break;
    }

    set_menu(menu);
}

static void menu_process_leftright(bool left)
{
    int8_t increment = left?(-1):1;

    if (menu_editing)
	menu_edit_new_field(menu_editing_field+increment, left);
    else {
	if (left)
	    menu_navigate_back();
	else
	    menu_navigate_into();
    }
}

static void menu_process_updown(bool up)
{
    int8_t increment = up?1:(-1);

    if (menu_editing) {
	increment_value(increment);
	menu_draw_row(menu_row);
    } else {
	if (up)
	    menu_navigate_up();
	else
	    menu_navigate_down();
    }
}

#define GRAPH_POINTS 128
//#define GRAPH_POINTS 128
//#define GRAPH_POINTS 12
#define GRAPH_START_X 0

#define GRAPH_HEIGHT (GRAPH_PAGES * 8)
#define GRAPH_PAGES 7
#define GRAPH_START_Y 1

//uint8_t graph_desired[GRAPH_POINTS+1];
//uint8_t graph_actual[GRAPH_POINTS+1];
uint8_t graph_actual[4];

static void minmax_mark(uint8_t *min_p, uint8_t *max_p, uint8_t mid)
{
    uint8_t min = *min_p;
    uint8_t max = *max_p;

    if (mid == 255) {
	*min_p = 255;
	return;
    }

    if (min == 255)
	min = mid;
    if (max == 255)
	max = mid;
    if (max < min) {
	uint8_t tmp = min;
	min = max;
	max = tmp;
    }
    *min_p = mid - (mid-min)/2;
    *max_p = (max-mid)/2 + mid;
}

temp_t graph_temp_min, graph_temp_range;
uint32_t time_per_unit;
uint8_t graph_cursor;

static uint8_t graph_value(temp_t temp);

static uint8_t graph_at(uint8_t col)
{
    return graph_value(temperature_at_time(col*time_per_unit));
}

static void graphics_draw_column(uint8_t col)
{
    uint8_t data;
    uint8_t pr_mid, pr_min, pr_max;
    uint8_t act_mid, act_min, act_max;
    uint8_t i;
    uint8_t page;
    uint8_t act_col;

    if (col >= GRAPH_POINTS)
	return;

    if (col == graph_cursor)
	act_col = 1;
    else
	act_col = 0;

    pr_mid = graph_at(col);
    pr_min = graph_at(col-1);
    pr_max = graph_at(col+1);

    minmax_mark(&pr_min, &pr_max, pr_mid);

    act_min = graph_actual[act_col];
    act_mid = graph_actual[act_col+1];
    act_max = graph_actual[act_col+2];

    minmax_mark(&act_min, &act_max, act_mid);

    if (col == 0) {
	pr_min = 0;
	pr_max = GRAPH_HEIGHT-1;
    }

    page = GRAPH_PAGES-1;
    for (i = 0; i < GRAPH_HEIGHT; i++) {
	data <<= 1;
	if ((i >= pr_min && i <= pr_max) ||
	    (i >= act_min && i <= act_max) ||
	    (i == 0)) {
		data |= 1;
	}
	if ((i & 0x7) == 7) {
	    if (graph_cursor == col)
		data |= 0x55;
	    display_setposition(col, GRAPH_START_Y + page);
	    display_data(1, &data);
	    page--;
	}
    }
}

static void graphics_draw_screen(void)
{
    int i;

    /* initialise profile */

    for (i = 0; i < GRAPH_POINTS; i++)
	graphics_draw_column(i);
}

static uint8_t __attribute__ ((noinline)) graph_value(temp_t temp)
{
    int32_t v;

    if (temp == INVALID_TEMPERATURE)
	v = 255;
    else
	v = ((int32_t)temp - graph_temp_min) * GRAPH_HEIGHT / graph_temp_range;

    return v;
}

static void graphics_init(void)
{
    uint8_t i;
    uint32_t total_time;
    temp_t temp_min, temp_max;
    uint8_t *graph_actual_p;

    run_status = RUN_STATUS_READY;

    temp_min = temp_max = get_profile_temperature(1);

    total_time = 0;

    for (i = 0; i < 6; i++) {
	temp_t temp = get_profile_temperature(i+2);
	uint32_t time = profile_time(i);
	if (time == 0)
	    continue;
	total_time += time;
	if (temp > temp_max)
	    temp_max = temp;
	if (temp < temp_min)
	    temp_min = temp;
    }

    time_per_unit = (total_time + GRAPH_POINTS - 1) / GRAPH_POINTS;

    temp_min -= 10 * 10;
    temp_max += 10 * 10;
    graph_temp_range = temp_max - temp_min;
    graph_temp_min = temp_min;

    graph_cursor = 255;

    graph_actual_p = &graph_actual[0];

    for (i = 0; i < 4; i++)
	*(graph_actual_p++) = 255;
}

static void graphics_poll(void)
{
    if (menu_redraw) {
	graphics_init();
	graphics_draw_screen();
    }
    if (run_status == RUN_STATUS_RUNNING) {
	uint8_t col = control_now() / time_per_unit;
	if (col <= GRAPH_POINTS) {
	    if (col != graph_cursor) {
		graph_actual[0] = graph_actual[1];
		graph_actual[1] = graph_actual[2];
	    }
	    graph_actual[2] = graph_value(therm_temp());
	} else {
	    run_status = RUN_STATUS_FINISHED;
	}
	graph_cursor = col;
	graphics_draw_column(col-1);
	graphics_draw_column(col);
    }
}

void menu_poll(void)
{
    uint8_t button_pressed;
    
    ATOMIC_BLOCK(ATOMIC_FORCEON) {
	button_pressed = button;
	button = 0;
    }

    if (button_pressed == BUTTON_LEFT || button_pressed == BUTTON_RIGHT)
	menu_process_leftright(button_pressed == BUTTON_LEFT);
    if (button_pressed == BUTTON_UP || button_pressed == BUTTON_DOWN)
	menu_process_updown(button_pressed == BUTTON_UP);

    if (menu_redraw || (menu_current == MENU_RUN_PROFILE) || (menu_current == MENU_MAIN)) {
	display_menu(menu_redraw);
	menu_set_fields(menu_row);
    }

    if (menu_current == MENU_RUN_PROFILE) {
	graphics_poll();
    }
    menu_redraw = FALSE;
}