Browse Source

Rework display support. Add unified system for all menus.

k4be 2 years ago
parent
commit
006f904ea0
10 changed files with 410 additions and 354 deletions
  1. 1 1
      soft/Makefile
  2. 44 84
      soft/display.c
  3. 16 19
      soft/display.h
  4. 15 10
      soft/main.c
  5. 166 0
      soft/menu.c
  6. 52 0
      soft/menu.h
  7. 21 68
      soft/settings.c
  8. 1 18
      soft/settings.h
  9. 89 137
      soft/working_modes.c
  10. 5 17
      soft/working_modes.h

+ 1 - 1
soft/Makefile

@@ -2,7 +2,7 @@
 PROJECT	= glg
 
 ### Source files and search directory
-CSRC    = main.c uart0.c uart1.c ff.c mmc.c 1wire.c ds18b20.c expander.c HD44780-I2C.c I2C.c xprintf.c gpx.c ffunicode.c display.c working_modes.o timec.o nmea.o settings.o
+CSRC    = main.c uart0.c uart1.c ff.c mmc.c 1wire.c ds18b20.c expander.c HD44780-I2C.c I2C.c xprintf.c gpx.c ffunicode.c display.c working_modes.o timec.o nmea.o settings.o menu.o
 ASRC    = stime.S
 VPATH   =
 

+ 44 - 84
soft/display.c

@@ -98,52 +98,50 @@ void battery_state_display(void) {
 	};
 }
 
-void disp_func_startup(__attribute__ ((unused)) unsigned char changed) {
-	strcpy_P(disp.line1, PSTR("Uruchamianie..."));
-}
-
-void disp_func_poweroff(__attribute__ ((unused)) unsigned char changed) {
-	strcpy_P(disp.line1, PSTR("Wylaczanie..."));
-}
-
-void disp_func_poweroff_lowbat(unsigned char changed) {
-	disp_func_poweroff(changed);
-	strcpy_P(disp.line2, PSTR("Bateria slaba!"));
-}
-
-void disp_func_start_message(__attribute__ ((unused)) unsigned char changed) {
-	strcpy_P(disp.line1, PSTR("Start"));
-	switch(System.status){
-		case STATUS_NO_POWER: case STATUS_OK: case STATUS_NO_GPS: disp.line2[0] = '\0'; break;
-		case STATUS_NO_DISK:			strcpy_P(disp.line2, PSTR("Brak karty!")); break;
-		case STATUS_DISK_ERROR:			strcpy_P(disp.line2, PSTR("Blad karty!")); break;
-		case STATUS_FILE_WRITE_ERROR:	strcpy_P(disp.line2, PSTR("Blad zapisu!")); break;
-		case STATUS_FILE_SYNC_ERROR:	strcpy_P(disp.line2, PSTR("Blad zapisu FAT!")); break;
-		case STATUS_FILE_CLOSE_ERROR:	strcpy_P(disp.line2, PSTR("Blad zamk.pliku!")); break;
-		case STATUS_FILE_OPEN_ERROR:	strcpy_P(disp.line2, PSTR("Blad otw. pliku!")); break;
-	}
-}
-
 __flash const char _gps_wait[] =		"Czekam na GPS...";
 __flash const char _gps_ok[] =			"GPS OK!";
 __flash const char _card_ok[] =			"Karta OK!";
 __flash const char _logging_active[] =	"Zapis aktywny";
 __flash const char _logging_paused[] =	"Zapis wstrzymany";
 
-void disp_func_card_ok(__attribute__ ((unused)) unsigned char changed) {
-	strcpy_P(disp.line1, _card_ok);
-	strcpy_P(disp.line2, _gps_wait);
-}
-
-void disp_func_file_open(__attribute__ ((unused)) unsigned char changed) {
-	strcpy_P(disp.line2, _logging_active);
-}
-
-void disp_func_file_closed(__attribute__ ((unused)) unsigned char changed) {
-	strcpy_P(disp.line2, PSTR("Pliki zamkniete"));
+void display_event(unsigned char event) { /* overrides display with current messages */
+	switch (event) {
+		case DISPLAY_EVENT_STARTUP:
+			strcpy_P(disp.line1, PSTR("Uruchamianie..."));
+			break;
+		case DISPLAY_EVENT_LOW_BATTERY:
+			strcpy_P(disp.line2, PSTR("Bateria slaba!"));
+		/* fall through */
+		case DISPLAY_EVENT_POWEROFF:
+			strcpy_P(disp.line1, PSTR("Wylaczanie..."));
+			break;
+		case DISPLAY_EVENT_INITIALIZED:
+			strcpy_P(disp.line1, PSTR("Start"));
+			switch(System.status){
+				case STATUS_NO_POWER: case STATUS_OK: case STATUS_NO_GPS: disp.line2[0] = '\0'; break;
+				case STATUS_NO_DISK:			strcpy_P(disp.line2, PSTR("Brak karty!")); break;
+				case STATUS_DISK_ERROR:			strcpy_P(disp.line2, PSTR("Blad karty!")); break;
+				case STATUS_FILE_WRITE_ERROR:	strcpy_P(disp.line2, PSTR("Blad zapisu!")); break;
+				case STATUS_FILE_SYNC_ERROR:	strcpy_P(disp.line2, PSTR("Blad zapisu FAT!")); break;
+				case STATUS_FILE_CLOSE_ERROR:	strcpy_P(disp.line2, PSTR("Blad zamk.pliku!")); break;
+				case STATUS_FILE_OPEN_ERROR:	strcpy_P(disp.line2, PSTR("Blad otw. pliku!")); break;
+			}
+			break;
+		case DISPLAY_EVENT_CARD_INITIALIZED:
+			strcpy_P(disp.line1, _card_ok);
+			strcpy_P(disp.line2, _gps_wait);
+			break;
+		case DISPLAY_EVENT_FILE_CLOSED:
+			strcpy_P(disp.line2, PSTR("Pliki zamkniete"));
+			break;
+		case DISPLAY_EVENT_FILE_OPEN:
+			strcpy_P(disp.line2, PSTR("Pliki otwarte"));
+			break;
+	}
+	display_refresh(1);
 }
 
-void disp_func_main_default(__attribute__ ((unused)) unsigned char changed) {
+void disp_func_main_default(void) {
 	if (FLAGS & F_FILEOPEN) {
 		if (System.tracking_paused)
 			strcpy_P(disp.line1, _logging_paused);
@@ -158,7 +156,7 @@ void disp_func_main_default(__attribute__ ((unused)) unsigned char changed) {
 		strcpy_P(disp.line2, _gps_wait);
 }
 
-void disp_func_coord(__attribute__ ((unused)) unsigned char changed) {
+void disp_func_coord(void) {
 	if (System.location_valid == LOC_INVALID) {
 		strcpy_P(disp.line1, PSTR("??? N/S"));
 		strcpy_P(disp.line2, PSTR("??? E/W"));
@@ -168,7 +166,7 @@ void disp_func_coord(__attribute__ ((unused)) unsigned char changed) {
 	xsprintf(disp.line2, PSTR("%3.6f%c"), (location.lon < 0)?(-location.lon):location.lon, (location.lon < 0)?'W':'E');
 }
 
-void disp_func_ele_sat(__attribute__ ((unused)) unsigned char changed) {
+void disp_func_ele_sat(void) {
 	if (System.location_valid == LOC_INVALID) {
 		strcpy_P(disp.line1, PSTR("ele = ???"));
 	} else {
@@ -179,7 +177,7 @@ void disp_func_ele_sat(__attribute__ ((unused)) unsigned char changed) {
 		strcat_P(disp.line2, PSTR(", DGPS"));
 }
 
-void disp_distance_and_time(__attribute__ ((unused)) unsigned char changed) {
+void disp_distance_and_time(void) {
 	xsprintf(disp.line1, PSTR("%.2f km"), (float)System.distance / 100000.0);
 	if (utc > 0 && System.time_start > 0) {
 		xsprintf(disp.line2, PSTR("t=%u s"), (unsigned int)(utc - System.time_start));
@@ -188,7 +186,7 @@ void disp_distance_and_time(__attribute__ ((unused)) unsigned char changed) {
 	}
 }
 
-void disp_speed(__attribute__ ((unused)) unsigned char changed) {
+void disp_speed(void) {
 	strcpy_P(disp.line1, PSTR("Predkosc:"));
 	if (utc > 0 && System.time_start > 0) {
 		xsprintf(disp.line2, PSTR("%.2f km/h"), (float)System.distance / (float)(utc - System.time_start) * 0.036);
@@ -197,7 +195,7 @@ void disp_speed(__attribute__ ((unused)) unsigned char changed) {
 	}
 }
 
-void disp_time(__attribute__ ((unused)) unsigned char changed) {
+void disp_time(void) {
 	if (utc == 0) {
 		strcpy_P(disp.line1, PSTR("?"));
 		strcpy_P(disp.line2, PSTR("?"));
@@ -211,7 +209,7 @@ void disp_time(__attribute__ ((unused)) unsigned char changed) {
 	xsprintf(disp.line2, PSTR("%d:%02d:%02d"), ct->tm_hour, ct->tm_min, ct->tm_sec);
 }
 
-void disp_func_temperature(__attribute__ ((unused)) unsigned char changed) {
+void disp_func_temperature(void) {
 	strcpy_P(disp.line1, PSTR("Temperatura"));
 	if (System.temperature_ok) {
 		xsprintf(disp.line2, PSTR("%.1f stC"), System.temperature);
@@ -219,48 +217,15 @@ void disp_func_temperature(__attribute__ ((unused)) unsigned char changed) {
 		strcpy_P(disp.line2, PSTR("Blad!"));
 	}
 }
-void disp_func_main_menu(__attribute__ ((unused)) unsigned char changed) {
-	display_main_menu_item();
-}
-
-void disp_func_settings_menu(__attribute__ ((unused)) unsigned char changed) {
-	display_settings_menu_item();
-}
 
-void (*__flash const disp_funcs[])(unsigned char) = {
-	[DISPLAY_STATE_STARTUP] = disp_func_startup,
-	[DISPLAY_STATE_POWEROFF] = disp_func_poweroff,
-	[DISPLAY_STATE_POWEROFF_LOWBAT] = disp_func_poweroff_lowbat,
-	[DISPLAY_STATE_START_MESSAGE] = disp_func_start_message,
-	[DISPLAY_STATE_CARD_OK] = disp_func_card_ok,
-	[DISPLAY_STATE_FILE_OPEN] = disp_func_file_open,
-	[DISPLAY_STATE_FILE_CLOSED] = disp_func_file_closed,
-	[DISPLAY_STATE_MAIN_DEFAULT] = disp_func_main_default,
-	[DISPLAY_STATE_COORD] = disp_func_coord,
-	[DISPLAY_STATE_ELE_SAT] = disp_func_ele_sat,
-	[DISPLAY_STATE_DIST_TIME] = disp_distance_and_time,
-	[DISPLAY_STATE_SPEED] = disp_speed,
-	[DISPLAY_STATE_TIME] = disp_time,
-	[DISPLAY_STATE_MAIN_MENU] = disp_func_main_menu,
-	[DISPLAY_STATE_SETTINGS_MENU] = disp_func_settings_menu,
-	[DISPLAY_STATE_TEMPERATURE] = disp_func_temperature,
-};
-
-void display_refresh(unsigned char newstate) {
-	unsigned char changed = 0;
-
-	if (newstate)
-		changed = 1;
-	
-	disp_funcs[System.display_state](changed);
-	
+void display_refresh(unsigned char changed) {
 	if (timer_expired(lcd)) {
 		changed = 1;
-		set_timer(lcd, 1000);
 	}
 
 	/* write to LCD */
 	if (changed) {
+		set_timer(lcd, 1000);
 		battery_state_display();
 		unsigned char len;
 		LCD_GoTo(0,0);
@@ -281,8 +246,3 @@ void display_refresh(unsigned char newstate) {
 	}
 }
 
-void display_state(unsigned char newstate) {
-	System.display_state = newstate;
-	display_refresh(newstate);
-}
-

+ 16 - 19
soft/display.h

@@ -1,22 +1,12 @@
 #pragma once
 
-#define DISPLAY_STATE_NO_CHANGE	0
-#define DISPLAY_STATE_STARTUP	1
-#define DISPLAY_STATE_POWEROFF	2
-#define DISPLAY_STATE_POWEROFF_LOWBAT	3
-#define DISPLAY_STATE_START_MESSAGE	4
-#define DISPLAY_STATE_CARD_OK	5
-#define DISPLAY_STATE_FILE_OPEN	6
-#define DISPLAY_STATE_FILE_CLOSED	7
-#define DISPLAY_STATE_MAIN_DEFAULT	8
-#define DISPLAY_STATE_COORD	9
-#define DISPLAY_STATE_ELE_SAT	10
-#define DISPLAY_STATE_DIST_TIME	11
-#define DISPLAY_STATE_SPEED	12
-#define DISPLAY_STATE_TIME	13
-#define DISPLAY_STATE_MAIN_MENU	14
-#define DISPLAY_STATE_SETTINGS_MENU	15
-#define DISPLAY_STATE_TEMPERATURE 16
+#define DISPLAY_EVENT_STARTUP		0
+#define DISPLAY_EVENT_POWEROFF		1
+#define DISPLAY_EVENT_LOW_BATTERY	2
+#define DISPLAY_EVENT_INITIALIZED	3
+#define DISPLAY_EVENT_CARD_INITIALIZED	4
+#define DISPLAY_EVENT_FILE_OPEN		5
+#define DISPLAY_EVENT_FILE_CLOSED	6
 
 struct disp_s {
 	char line1[16];
@@ -26,6 +16,13 @@ struct disp_s {
 extern struct disp_s disp;
 
 void disp_init(void);
-void display_refresh(unsigned char newstate);
-void display_state(unsigned char newstate);
+void display_event(unsigned char event);
+void display_refresh(unsigned char changed);
+void disp_func_main_default(void);
+void disp_func_coord(void);
+void disp_func_ele_sat(void);
+void disp_distance_and_time(void);
+void disp_speed(void);
+void disp_time(void);
+void disp_func_temperature(void);
 

+ 15 - 10
soft/main.c

@@ -28,6 +28,7 @@
 #include "timec.h"
 #include "nmea.h"
 #include "settings.h"
+#include "menu.h"
 
 /*FUSES = {0xFF, 0x11, 0xFE};*/		/* ATmega644PA fuses: Low, High, Extended.
 This is the fuse settings for this project. The fuse bits will be included
@@ -49,7 +50,7 @@ void start_bootloader(void) {
 	cli();
 	uart1_deinit();
 /*	close_files(0); // FIXME not working
-	display_state(DISPLAY_STATE_BOOTLOADER);*/
+	display_event(DISPLAY_EVENT_BOOTLOADER);*/
 	LCD_Clear(); /* Do not call display.c here! */
 	LCD_GoTo(0,0);
 	LCD_WriteTextP(PSTR("Aktualizacja"));
@@ -263,7 +264,7 @@ void close_files(unsigned char flush_logs) {
 		if (f_close(&system_log))
 			System.status = STATUS_FILE_CLOSE_ERROR;
 		xputs_P(PSTR("File closed\r\n"));
-		display_state(DISPLAY_STATE_FILE_CLOSED);
+		display_event(DISPLAY_EVENT_FILE_CLOSED);
 	}
 	FLAGS &= ~F_FILEOPEN;
 	disk_ioctl(0, CTRL_POWER, 0);
@@ -287,16 +288,18 @@ int main (void)
 	xdev_out(log_put);
 	xputs_P(PSTR("STARTUP\r\n"));
 	disp_init();
-	display_state(DISPLAY_STATE_STARTUP);
+	display_event(DISPLAY_EVENT_STARTUP);
 	settings_load();
 	
+	menu_push(default_menu);
+	
 	for (;;) {
 		wdt_reset();
 		if (FLAGS & (F_POWEROFF | F_LVD)) {
 			xputs_P(PSTR("POWEROFF\r\n"));
-			display_state(DISPLAY_STATE_POWEROFF);
+			display_event(DISPLAY_EVENT_POWEROFF);
 			if (FLAGS & F_LVD) {
-				display_state(DISPLAY_STATE_POWEROFF_LOWBAT);
+				display_event(DISPLAY_EVENT_LOW_BATTERY);
 				_delay_ms(500);
 			}
 			POWEROFF();
@@ -307,7 +310,7 @@ int main (void)
 			xputs_P(PSTR("RESTART\r\n"));
 		}
 
-		display_state(DISPLAY_STATE_START_MESSAGE);
+		display_event(DISPLAY_EVENT_INITIALIZED);
 		xprintf(PSTR("LOOP err=%u\r\n"), (unsigned int)System.status);
 		utc = 0;
 		localtime = 0;
@@ -336,7 +339,7 @@ int main (void)
 		}
 		System.status = STATUS_NO_GPS;
 		xputs(PSTR("FS Ok\r\n"));
-		display_state(DISPLAY_STATE_CARD_OK);
+		display_event(DISPLAY_EVENT_CARD_INITIALIZED);
 		beep(50, 1);				/* 1 beep */
 
 		/* Initialize GPS receiver */
@@ -353,9 +356,11 @@ int main (void)
 
 		for (;;) { /* main loop */
 			wdt_reset();
-			display_refresh(DISPLAY_STATE_NO_CHANGE);
 			gettemp();
-			key_process();
+			display_refresh(menu());
+			if (no_menu())
+				menu_push(default_menu); /* returned from top-level */
+
 			if (System.timers.backlight)
 				LEDW_ON();
 			else
@@ -462,7 +467,7 @@ int main (void)
 				FLAGS |= F_FILEOPEN;
 				System.status = STATUS_OK;
 				beep(50, System.tracking_paused?5:2);		/* Two beeps. Start logging. */
-				display_state(DISPLAY_STATE_FILE_OPEN);
+				display_event(DISPLAY_EVENT_FILE_OPEN);
 				continue;
 			}
 		}

+ 166 - 0
soft/menu.c

@@ -0,0 +1,166 @@
+#include "main.h"
+#include "menu.h"
+#include "settings.h"
+#include "display.h"
+#include "xprintf.h"
+
+unsigned char __menu_num; // Menu stack variables
+struct menu_struct __menu_data[DATA_NUM];
+__flash const char _NULL_STRING[] = "(NULL)";
+
+void settings_display_bool(unsigned char index) {
+	unsigned char val = get_flag(index);
+	if (val)
+		strcpy_P(disp.line2, PSTR("< Tak > "));
+	else
+		strcpy_P(disp.line2, PSTR("< Nie > "));
+	strcat_P(disp.line2, HAVE_NEXT_SETTING_POSITION?PSTR(" \x01"):PSTR("  ")); /* down arrow */
+	strcat_P(disp.line2, HAVE_PREV_SETTING_POSITION?PSTR(" \x02"):PSTR("  ")); /* up arrow */
+}
+
+void settings_display_u8(unsigned char index) {
+	unsigned char val = System.conf.conf_u8[index];
+	
+	xsprintf(disp.line2, PSTR("%d"), (int)val);
+	strcat_P(disp.line2, HAVE_NEXT_SETTING_POSITION?PSTR(" \x01"):PSTR("  ")); /* down arrow */
+	strcat_P(disp.line2, HAVE_PREV_SETTING_POSITION?PSTR(" \x02"):PSTR("  ")); /* up arrow */
+}
+
+void settings_change_bool(struct menu_pos pos, unsigned char k) {
+	unsigned char index = pos.index;
+	unsigned char val = get_flag(index);
+
+	if (k ==  K_LEFT || k ==  K_RIGHT) { /* change value */
+		val = !val;
+		set_flag(index, val);
+		if (pos.changed != NULL)
+			pos.changed();
+	}
+}
+
+void settings_change_u8(struct menu_pos pos, unsigned char k) {
+	unsigned char index = pos.index;
+	unsigned char val = System.conf.conf_u8[index];
+
+	if (k == K_LEFT) {
+		if (val)
+			val--;
+	}
+
+	if (k == K_RIGHT) {
+		if (val < limits_max_u8[index])
+			val++;
+	}
+
+	if (k ==  K_LEFT || k ==  K_RIGHT) {
+		System.conf.conf_u8[index] = val;
+		if (pos.changed != NULL)
+			pos.changed();
+	}
+}
+
+unsigned char menu(void) {
+	struct menu_struct *curr;
+	struct menu_pos pos;
+	unsigned char display_line1_as_string = 0;
+	unsigned char display_changed = 0;
+	
+	unsigned char k = getkey();
+	
+	curr = menu_get();
+	pos = curr->list[curr->ind];
+
+	switch (k) {
+		case K_UP:
+			if (curr->ind > 0) {
+				curr->ind--;
+				pos = curr->list[curr->ind];
+				display_changed = 1;
+			}
+			break;
+		case K_DOWN:
+			if (curr->ind < curr->num-1) {
+				curr->ind++;
+				pos = curr->list[curr->ind];
+				display_changed = 1;
+			}
+			break;
+	}
+	
+	switch (pos.display_type) {
+		case MENU_DISPLAY_TYPE_DEFAULT:
+			if (IS_SETTING(pos.type))
+				break;
+		/* fall through */
+		case MENU_DISPLAY_TYPE_STRING:
+			display_line1_as_string = 1;
+			if (pos.value) {
+				strcpy_P(disp.line2, pos.value);
+			} else {
+				strcpy_P(disp.line2, _NULL_STRING);
+			}
+			break;
+		case MENU_DISPLAY_TYPE_NAME_FUNCTION:
+			display_line1_as_string = 1;
+		/* fall through */
+		case MENU_DISPLAY_TYPE_FUNCTION:
+			pos.display();
+			break;
+		case MENU_DISPLAY_TYPE_NAME_CSFUNCTION:
+			display_line1_as_string = 1;
+			strcpy_P(disp.line2, pos.csdisplay());
+			break;
+		default:	/* bad data */
+			break;
+	}
+	
+	switch (pos.type) {
+		case MENU_TYPE_SETTING_BOOL:
+			if (pos.display_type == MENU_DISPLAY_TYPE_DEFAULT) {
+				settings_display_bool(pos.index);
+				display_line1_as_string = 1;
+			}
+			if (k) {
+				settings_change_bool(pos, k);
+				display_changed = 1;
+			}
+			break;
+		case MENU_TYPE_SETTING_U8:
+			if (pos.display_type == MENU_DISPLAY_TYPE_DEFAULT) {
+				settings_display_u8(pos.index);
+				display_line1_as_string = 1;
+			}
+			if (k) {
+				settings_change_u8(pos, k);
+				display_changed = 1;
+			}
+			break;
+		case MENU_TYPE_DISPLAY:
+			/* nothing special to do */
+			break;
+		case MENU_TYPE_FUNCTION:
+			if (k == K_RIGHT) {
+				pos.func();
+				display_changed = 1;
+			}
+			break;
+	}
+	
+	if (pos.allow_back && k == K_LEFT) {
+		menu_pop();
+		return 0;
+	}
+	
+	if (display_line1_as_string) {
+		if (pos.name) {
+			strcpy_P(disp.line1, pos.name);
+		} else {
+			strcpy_P(disp.line1, _NULL_STRING);
+		}
+	}
+	
+	if (display_changed)
+		set_timer(lcd, 50); /* ensure update on next iteration */
+	return 1;
+}
+

+ 52 - 0
soft/menu.h

@@ -0,0 +1,52 @@
+#pragma once
+
+#define MENU_TYPE_SETTING_BOOL	0
+#define MENU_TYPE_SETTING_U8	1
+#define MENU_TYPE_DISPLAY		2
+#define MENU_TYPE_FUNCTION		3
+
+#define IS_SETTING(x) (x<3)
+
+#define MENU_DISPLAY_TYPE_DEFAULT	0	// specific for setting type if IS_SETTING(), MENU_DISPLAY_STRING otherwise
+#define MENU_DISPLAY_TYPE_STRING	1
+#define MENU_DISPLAY_TYPE_FUNCTION	2
+#define MENU_DISPLAY_TYPE_NAME_FUNCTION	3
+#define MENU_DISPLAY_TYPE_NAME_CSFUNCTION	4
+
+#define menu_push(x) { if(__menu_num<DATA_NUM) __menu_data[__menu_num++] = x; } // stack commands
+#define menu_pop() --__menu_num
+#define menu_get() &__menu_data[__menu_num-1]
+#define no_menu() (__menu_num == 0)
+
+#define DATA_NUM 3 // maximum menu depth
+
+#define HAVE_NEXT_SETTING_POSITION	0
+#define HAVE_PREV_SETTING_POSITION	0
+
+struct menu_pos {
+	unsigned char type;
+	unsigned char display_type;
+	__flash const char *name;		// used for line 1 when MENU_DISPLAY_TYPE_STRING or MENU_DISPLAY_TYPE_NAME_(CS)FUNCTION
+	union {
+		__flash const char *value;	// used for line 2 when MENU_DISPLAY_TYPE_STRING
+		void (* display)(void);		// used for line 2 when MENU_DISPLAY_TYPE_NAME_FUNCTION; used for both lines when MENU_DISPLAY_TYPE_FUNCTION
+		__flash const char * (* csdisplay)(void);	// used for line 2 when MENU_DISPLAY_TYPE_NAME_CSFUNCTION
+	};
+	unsigned char index;			// index when IS_SETTING()
+	void (* changed)(void);			// what to call on changed value when IS_SETTING()
+	void (* func)(void);			// what to call on MENU_DISPLAY_TYPE_NAME_FUNCTION
+	unsigned char allow_back;		// left arrow will return to level up
+};
+
+struct menu_struct {
+	__flash const struct menu_pos *list;	// list of elements
+	unsigned char num;		// count of elements
+	signed int ind:6;		// current index/position
+};
+
+extern unsigned char __menu_num;
+extern struct menu_struct __menu_data[DATA_NUM];
+extern void (*func_enter_table[])(struct menu_pos *); // to be defined in the application
+
+unsigned char menu(void);
+

+ 21 - 68
soft/settings.c

@@ -5,6 +5,7 @@
 #include "xprintf.h"
 #include "working_modes.h"
 #include "nmea.h"
+#include "menu.h"
 
 EEMEM struct config_s config_eep;
 EEMEM unsigned char config_crc;
@@ -58,47 +59,6 @@ void settings_store(void) {
 	xputs_P(PSTR("EEPROM write done\r\n"));
 }
 
-void settings_display_and_modify_bool(unsigned char mindex, unsigned char k) {
-	unsigned char index = settings_menu[mindex].index;
-	unsigned char val = get_flag(index);
-	const __flash char *name = settings_menu[mindex].name;
-
-	if (k ==  K_LEFT || k ==  K_RIGHT) { /* change value */
-		val = !val;
-		set_flag(index, val);
-		if (settings_menu[mindex].changed != NULL)
-			settings_menu[mindex].changed();
-	}
-
-	strcpy_P(disp.line1, name);
-	settings_menu[mindex].display(val);
-}
-
-void settings_display_and_modify_u8(unsigned char mindex, unsigned char k) {
-	unsigned char index = settings_menu[mindex].index;
-	unsigned char val = System.conf.conf_u8[index];
-	const __flash char *name = settings_menu[mindex].name;
-
-	if (k == K_LEFT) {
-		if (val)
-			val--;
-	}
-
-	if (k == K_RIGHT) {
-		if (val < limits_max_u8[index])
-			val++;
-	}
-
-	if (k ==  K_LEFT || k ==  K_RIGHT) {
-		System.conf.conf_u8[index] = val;
-		if (settings_menu[mindex].changed != NULL)
-			settings_menu[mindex].changed();
-	}
-
-	strcpy_P(disp.line1, name);
-	settings_menu[mindex].display(val);
-}
-
 unsigned char get_flag(unsigned char index) {
 	volatile unsigned char *sptr = &System.conf.flags[index/8];
 	index %= 8;
@@ -115,25 +75,14 @@ void set_flag(unsigned char index, unsigned char val) {
 		*sptr &= ~_BV(index);
 }
 
-void settings_bool_disp_default(unsigned char val) {
-	if (val)
-		strcpy_P(disp.line2, PSTR("< Tak > "));
-	else
-		strcpy_P(disp.line2, PSTR("< Nie > "));
-	strcat_P(disp.line2, HAVE_NEXT_SETTING_POSITION?PSTR(" \x01"):PSTR("  ")); /* down arrow */
-	strcat_P(disp.line2, HAVE_PREV_SETTING_POSITION?PSTR(" \x02"):PSTR("  ")); /* up arrow */
-}
-
-void settings_u8_disp_default(unsigned char val) {
-	xsprintf(disp.line2, PSTR("%d"), (int)val);
-	strcat_P(disp.line2, HAVE_NEXT_SETTING_POSITION?PSTR(" \x01"):PSTR("  ")); /* down arrow */
-	strcat_P(disp.line2, HAVE_PREV_SETTING_POSITION?PSTR(" \x02"):PSTR("  ")); /* up arrow */
-}
-
 void display_gnss_mode(unsigned char val) {
 	strcpy_P(disp.line2, gnss_names[val]);
 }
 
+void display_current_gnss_mode(void) {
+	display_gnss_mode(System.conf.gnss_mode);
+}
+
 /* SETTINGS ITEMS */
 
 __flash const char _msg_disable_filters[] = "Nie filtruj";
@@ -143,45 +92,49 @@ __flash const char _msg_skip_points[] = "Pomin punkty";
 __flash const char _msg_logging_after_boot[] = "Zapis po wlacz.";
 __flash const char _msg_back[] = "< Powrot";
 
-__flash const struct settings_menu_pos_s settings_menu[SETTINGS_MENU_MAXPOS+1] = {
+__flash const struct menu_pos settings_menu_list[] = {
 	{
-		.type = SETTINGS_TYPE_BACK,
+		.type = MENU_TYPE_DISPLAY,
+		.display_type = MENU_DISPLAY_TYPE_STRING,
 		.name = _msg_back,
+		.allow_back = 1,
 	},
 	{
-		.type = SETTINGS_TYPE_BOOL,
+		.type = MENU_TYPE_SETTING_BOOL,
 		.name = _msg_disable_filters,
 		.index = CONFFLAG_DISABLE_FILTERS,
-		.display = settings_bool_disp_default,
 	},
 	{
-		.type = SETTINGS_TYPE_U8,
+		.type = MENU_TYPE_SETTING_U8,
 		.name = _msg_skip_points,
 		.index = CONF_U8_SKIP_POINTS,
-		.display = settings_u8_disp_default,
 	},
 	{
-		.type = SETTINGS_TYPE_BOOL,
+		.type = MENU_TYPE_SETTING_BOOL,
 		.name = _msg_enable_sbas,
 		.index = CONFFLAG_ENABLE_SBAS,
-		.display = settings_bool_disp_default,
 		.changed = gps_initialize,
 	},
 	{
-		.type = SETTINGS_TYPE_U8,
+		.type = MENU_TYPE_SETTING_U8,
+		.display_type = MENU_DISPLAY_TYPE_NAME_FUNCTION,
 		.name = _msg_gnss_type,
 		.index = CONF_U8_GNSS_MODE,
-		.display = display_gnss_mode,
+		.display = display_current_gnss_mode,
 		.changed = gps_initialize,
 	},
 	{
-		.type = SETTINGS_TYPE_BOOL,
+		.type = MENU_TYPE_SETTING_BOOL,
 		.name = _msg_logging_after_boot,
 		.index = CONFFLAG_LOGGING_AFTER_BOOT,
-		.display = settings_bool_disp_default,
 	},
 };
 
+__flash const struct menu_struct settings_menu = {
+	.list = settings_menu_list,
+	.num = sizeof(settings_menu_list) / sizeof(settings_menu_list[0]),
+};
+
 __flash const char gnss_gps_glonass_galileo[] = "GPS+GL.NS+GAL.EO";
 __flash const char gnss_gps[] = "GPS";
 __flash const char gnss_gps_galileo[] = "GPS+GALILEO";

+ 1 - 18
soft/settings.h

@@ -23,15 +23,6 @@
 #define GNSS_MODE_GPS_BEIDOU			4
 #define GNSS_MODE_BEIDOU				5
 
-#define SETTINGS_TYPE_BACK	0
-#define SETTINGS_TYPE_BOOL	1
-#define SETTINGS_TYPE_U8	2
-
-#define HAVE_NEXT_SETTING_POSITION (mp.settings_menu_pos < SETTINGS_MENU_MAXPOS)
-#define HAVE_PREV_SETTING_POSITION (mp.settings_menu_pos > 0)
-
-#define SETTINGS_MENU_MAXPOS	5
-
 struct config_s {
 	union {
 		unsigned char conf_u8[16];
@@ -43,17 +34,9 @@ struct config_s {
 	unsigned char flags[4];
 };
 
-struct settings_menu_pos_s {
-	unsigned char type;
-	__flash const char *name;
-	unsigned char index;
-	void (* changed)(void);
-	void (* display)(unsigned char);
-};
-
 extern const __flash unsigned char limits_max_u8[];
-extern __flash const struct settings_menu_pos_s settings_menu[SETTINGS_MENU_MAXPOS+1];
 extern __flash const char *gnss_names[];
+extern __flash const struct menu_struct settings_menu;
 
 unsigned char settings_load(void); /* 0 - ok, 1 - error */
 void settings_store(void);

+ 89 - 137
soft/working_modes.c

@@ -6,33 +6,20 @@
 #include "settings.h"
 #include "nmea.h"
 #include "gpx.h"
+#include "menu.h"
 
-static signed char display_mode_index;
 
-__flash const unsigned char main_display_modes[] = {
-	DISPLAY_STATE_MAIN_DEFAULT,
-	DISPLAY_STATE_COORD,
-	DISPLAY_STATE_ELE_SAT,
-	DISPLAY_STATE_DIST_TIME,
-	DISPLAY_STATE_SPEED,
-	DISPLAY_STATE_TIME,
-	DISPLAY_STATE_TEMPERATURE,
-};
-
-const char *enter_settings_get_name(void) {
-	return PSTR("> Ustawienia");
-}
+struct menu_params_s mp;
 
-unsigned char tracking_pause(void) {
+void tracking_pause(void) {
 	System.tracking_paused = !System.tracking_paused;
 	if (System.tracking_paused)
 		LEDB_ON();
 	else
 		LEDB_OFF();
-	return MODE_NO_CHANGE;
 }
 
-const char *pause_tracking_get_name(void) {
+__flash const char *pause_tracking_get_name(void) {
 	static unsigned char state = STATE_PAUSE_TRACKING_NOTPAUSED;
 	switch (state) {
 		default:
@@ -67,7 +54,7 @@ const char *pause_tracking_get_name(void) {
 	}
 }
 
-const char *save_point_get_name(void) {
+__flash const char *save_point_get_name(void) {
 	switch (mp.point_save_state) {
 		default:
 			return PSTR("> Zapisz punkt");
@@ -82,7 +69,7 @@ const char *save_point_get_name(void) {
 	}
 }
 
-unsigned char save_point(void) {
+void save_point(void) {
 	if (timer_expired(info_display)) { /* don't save too often */
 		if (System.location_valid) {
 			gpx_save_single_point(&location);
@@ -92,149 +79,114 @@ unsigned char save_point(void) {
 		}
 	}
 	set_timer(info_display, 2000);
-	return MODE_NO_CHANGE;
 }
 
-unsigned char new_file(void) {
+void new_file(void) {
 	System.open_new_file = 1;
-	return MODE_NO_CHANGE;
 }
 
-const char *new_file_get_name(void) {
-	return PSTR("> Nowy plik");
-}
+__flash const char _menu_header[] = "  *** MENU *** ";
+__flash const char _settings[] = "> Ustawienia";
+__flash const char _new_file[] = "> Nowy plik";
 
-__flash const struct main_menu_pos_s main_menu[MAIN_MENU_MAXPOS+1] = {
+__flash const struct menu_pos main_menu_list[] = {
 	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_NAME_CSFUNCTION,
+		.name = _menu_header,
+		.csdisplay = save_point_get_name,
 		.func = save_point,
-		.get_name = save_point_get_name,
+		.allow_back = 1,
 	},
 	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_STRING,
+		.name = _menu_header,
+		.value = _settings,
 		.func = enter_settings,
-		.get_name = enter_settings_get_name,
+		.allow_back = 1,
 	},
 	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_NAME_CSFUNCTION,
+		.name = _menu_header,
+		.csdisplay = pause_tracking_get_name,
 		.func = tracking_pause,
-		.get_name = pause_tracking_get_name,
+		.allow_back = 1,
 	},
 	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_STRING,
+		.name = _menu_header,
+		.value = _new_file,
 		.func = new_file,
-		.get_name = new_file_get_name,
+		.allow_back = 1,
 	},
 };
 
-struct menu_params_s mp;
-
-void change_display_mode(signed char dir) {
-	display_mode_index += dir;
-	if (display_mode_index < 0)
-		display_mode_index = sizeof(main_display_modes) - 1;
-	if (display_mode_index >= (signed char)sizeof(main_display_modes))
-		display_mode_index = 0;
-}
-
-unsigned char working_mode_default(unsigned char k) {
-	switch (k) {
-		case K_UP:
-			change_display_mode(-1);
-			break;
-		case K_DOWN:
-			change_display_mode(1);
-			break;
-		case K_RIGHT:
-			return MODE_MAIN_MENU;
-	}
-	display_state(main_display_modes[display_mode_index]);
-	return MODE_NO_CHANGE;
-}
-
-unsigned char working_mode_main_menu(unsigned char k) {
-	switch (k) {
-		case K_LEFT:
-			return MODE_DEFAULT;
-		case K_RIGHT:
-			if (main_menu[mp.main_menu_pos].func)
-				return main_menu[mp.main_menu_pos].func();
-			break;
-		case K_DOWN:
-			if (mp.main_menu_pos < MAIN_MENU_MAXPOS)
-				mp.main_menu_pos++;
-			break;
-		case K_UP:
-			if (mp.main_menu_pos > 0)
-				mp.main_menu_pos--;
-			break;
-	}
-	display_state(DISPLAY_STATE_MAIN_MENU);
-	return MODE_NO_CHANGE;
-}
-
-unsigned char working_mode_settings_menu(unsigned char k) {
-	switch (k) {
-		case K_LEFT:
-			if (settings_menu[mp.settings_menu_pos].type == SETTINGS_TYPE_BACK)
-				return MODE_MAIN_MENU;
-			/* fall through */
-		case K_RIGHT:
-			switch (settings_menu[mp.settings_menu_pos].type) {
-				case SETTINGS_TYPE_BOOL: settings_display_and_modify_bool(mp.settings_menu_pos, k); break;
-				case SETTINGS_TYPE_U8: settings_display_and_modify_u8(mp.settings_menu_pos, k); break;
-			}
-			break;
-		case K_DOWN:
-			if (mp.settings_menu_pos < SETTINGS_MENU_MAXPOS)
-				mp.settings_menu_pos++;
-			break;
-		case K_UP:
-			if (mp.settings_menu_pos > 0)
-				mp.settings_menu_pos--;
-			break;
-	}
-	return MODE_NO_CHANGE;
-}
-
-
-void display_main_menu_item(void) {
-	strcpy_P(disp.line1, PSTR("  *** MENU *** "));
-	strcpy_P(disp.line2, main_menu[mp.main_menu_pos].get_name());
-}
+__flash const struct menu_struct main_menu = {
+	.list = main_menu_list,
+	.num = sizeof(main_menu_list) / sizeof(main_menu_list[0]),
+};
 
-void display_settings_menu_item(void) {
-	switch (settings_menu[mp.settings_menu_pos].type) {
-		case SETTINGS_TYPE_BOOL:
-			settings_display_and_modify_bool(mp.settings_menu_pos, 0);
-			break;
-		case SETTINGS_TYPE_U8:
-			settings_display_and_modify_u8(mp.settings_menu_pos, 0);
-			break;
-		case SETTINGS_TYPE_BACK:
-			strcpy_P(disp.line1, PSTR("* Ustawienia *"));
-			strcpy_P(disp.line2, settings_menu[mp.settings_menu_pos].name);
-			if (HAVE_NEXT_SETTING_POSITION)
-				strcat_P(disp.line2, PSTR(" \x01")); /* down arrow */
-			if (HAVE_PREV_SETTING_POSITION)
-				strcat_P(disp.line2, PSTR(" \x02")); /* up arrow */
-			break;
-	};
-}
+__flash const struct menu_pos default_menu_list[] = {
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_func_main_default,
+		.func = enter_main_menu,
+	},
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_func_coord,
+		.func = enter_main_menu,
+	},
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_func_ele_sat,
+		.func = enter_main_menu,
+	},
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_distance_and_time,
+		.func = enter_main_menu,
+	},
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_speed,
+		.func = enter_main_menu,
+	},
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_time,
+		.func = enter_main_menu,
+	},
+	{
+		.type = MENU_TYPE_FUNCTION,
+		.display_type = MENU_DISPLAY_TYPE_FUNCTION,
+		.display = disp_func_temperature,
+		.func = enter_main_menu,
+	},
+};
 
-unsigned char (*__flash const working_modes[])(unsigned char) = {
-	working_mode_default,
-	working_mode_main_menu,
-	working_mode_settings_menu,
+__flash const struct menu_struct default_menu = {
+	.list = default_menu_list,
+	.num = sizeof(default_menu_list) / sizeof(default_menu_list[0]),
 };
 
-void key_process(void) {
-	unsigned char k = getkey();
-	unsigned char newmode = working_modes[System.working_mode](k);
-	if (newmode != MODE_NO_CHANGE && newmode != System.working_mode) {
-		LCD_Clear();
-		System.working_mode = newmode;
-	}
+
+void enter_settings(void) {
+	xprintf(PSTR("ENTER SETTINGS MENU, %d\r\n"), (int)__menu_num);
+	menu_push(settings_menu);
 }
 
-unsigned char enter_settings(void) {
-	display_state(DISPLAY_STATE_SETTINGS_MENU);
-	return MODE_SETTINGS_MENU;
+void enter_main_menu(void) {
+	xprintf(PSTR("ENTER MAIN MENU, %d\r\n"), (int)__menu_num);
+	menu_push(main_menu);
 }
 

+ 5 - 17
soft/working_modes.h

@@ -1,12 +1,5 @@
 #pragma once
 
-#define MODE_NO_CHANGE	0xff
-#define MODE_DEFAULT	0
-#define MODE_MAIN_MENU	1
-#define MODE_SETTINGS_MENU	2
-
-#define MAIN_MENU_MAXPOS 3
-
 #define STATE_PAUSE_TRACKING_NOTPAUSED	0
 #define STATE_PAUSE_TRACKING_JUSTPAUSED	1
 #define STATE_PAUSE_TRACKING_PAUSED		2
@@ -16,23 +9,18 @@
 #define STATE_POINT_SAVE_NOT_DONE	1
 #define STATE_POINT_SAVE_DONE	2
 
-struct main_menu_pos_s {
-	const char * (* get_name)(void);
-	unsigned char (* func)(void);
-};
+extern __flash const struct menu_struct default_menu;
 
 struct menu_params_s {
-	unsigned char main_menu_pos;
-	unsigned char settings_menu_pos;
 	unsigned char point_save_state;
 };
 
 extern struct menu_params_s mp;
 
+
 void key_process(void);
-unsigned char enter_settings(void);
-void display_settings_menu_item(void);
-void display_main_menu_item(void);
+void enter_settings(void);
+void enter_main_menu(void);
 
-unsigned char tracking_pause(void);
+void tracking_pause(void);