Преглед изворни кода

Add settings menu with boolean setting item.
Allow disabling data filters.

k4be пре 2 година
родитељ
комит
601efede12
11 измењених фајлова са 338 додато и 64 уклоњено
  1. 5 3
      soft/Makefile
  2. 39 7
      soft/display.c
  3. 9 0
      soft/display.h
  4. 56 50
      soft/gpx.c
  5. 9 0
      soft/main.c
  6. 6 3
      soft/main.h
  7. 6 0
      soft/nmea.c
  8. 78 0
      soft/settings.c
  9. 24 0
      soft/settings.h
  10. 83 1
      soft/working_modes.c
  11. 23 0
      soft/working_modes.h

+ 5 - 3
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
+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
 ASRC    = stime.S
 VPATH   =
 
@@ -60,7 +60,7 @@ PROJECT   := $(OBJDIR)/$(PROJECT)
 CFLAGS += -g$(DEBUG)
 CFLAGS += -mmcu=$(DEVICE)
 CFLAGS += -O$(OPTIMIZE) -mcall-prologues
-CFLAGS += $(addprefix -W,$(WARNINGS))
+CFLAGS += $(addprefix -W,$(WARNINGS)) --param=min-pagesize=0
 CFLAGS += $(addprefix -I,$(INCDIRS))
 CFLAGS += $(addprefix -D,$(DEFS))
 CFLAGS += -Wp,-MM,-MP,-MT,$(OBJDIR)/$(*F).o,-MF,$(OBJDIR)/$(*F).d
@@ -108,7 +108,8 @@ version :
 # Create final output file from ELF output file.
 %.hex: %.elf
 	@echo
-	$(OBJCOPY) -j .text -j .data -j .eeprom -j .fuse -O $(HEXFMT) $< $@
+#	$(OBJCOPY) -j .text -j .data -j .eeprom -j .fuse -O $(HEXFMT) $< $@
+	$(OBJCOPY) -j .text -j .data -O $(HEXFMT) $< $@
 
 %.bin: %.elf
 	@echo
@@ -128,6 +129,7 @@ version :
 size:
 	@echo
 	$(SIZE) $(PROJECT).elf
+	$(SIZE) $(PROJECT).hex
 
 
 # Link: create ELF output file from object files.

+ 39 - 7
soft/display.c

@@ -3,6 +3,7 @@
 #include "display.h"
 #include "HD44780-I2C.h"
 #include "xprintf.h"
+#include "working_modes.h"
 
 __flash const unsigned char battery_states[][8] = {
 	{
@@ -47,10 +48,35 @@ __flash const unsigned char battery_states[][8] = {
 	},
 };
 
-struct disp_s {
-	char line1[16];
-	char line2[17];
-} disp;
+__flash const unsigned char custom_chars[] = {
+	0b00000, /* 0x01 down arrow */
+	0b00100,
+	0b00100,
+	0b00100,
+	0b10101,
+	0b01110,
+	0b00100,
+	0b00000,
+	
+	0b00000, /* 0x02 up arrow */
+	0b00100,
+	0b01110,
+	0b10101,
+	0b00100,
+	0b00100,
+	0b00100,
+	0b00000,
+};
+
+struct disp_s disp;
+
+void disp_init(void) { /* send custom characters starting with 0x01 */
+	unsigned char i;
+	LCD_WriteCommand(0x40 + 8); // 0x01
+	for(i=0; i<sizeof(custom_chars); i++){
+		LCD_WriteData(custom_chars[i]);
+	};
+}
 
 void battery_state_display(void) {
 	unsigned char i;
@@ -143,13 +169,18 @@ void disp_func_ele_sat(__attribute__ ((unused)) unsigned char changed) {
 	} else {
 		xsprintf(disp.line1, PSTR("ele = %.1fm"), location.alt);
 	}
-	xsprintf(disp.line2, PSTR("%d satelit"), System.satellites_used);
+	xsprintf(disp.line2, PSTR("%2d satelit"), System.satellites_used);
+	if (System.sbas)
+		strcat_P(disp.line2, PSTR(", DGPS"));
 }
 
 void disp_func_main_menu(__attribute__ ((unused)) unsigned char changed) {
 	strcpy_P(disp.line1, PSTR("  *** MENU *** "));
-	disp.line2[0] = '>';
-	disp.line2[1] = '\0';
+	strcpy_P(disp.line2, PSTR("> Ustawienia"));
+}
+
+void disp_func_settings_menu(__attribute__ ((unused)) unsigned char changed) {
+	display_settings_menu_item();
 }
 
 void (*__flash const disp_funcs[])(unsigned char) = {
@@ -164,6 +195,7 @@ void (*__flash const disp_funcs[])(unsigned char) = {
 	[DISPLAY_STATE_COORD] = disp_func_coord,
 	[DISPLAY_STATE_ELE_SAT] = disp_func_ele_sat,
 	[DISPLAY_STATE_MAIN_MENU] = disp_func_main_menu,
+	[DISPLAY_STATE_SETTINGS_MENU] = disp_func_settings_menu,
 };
 
 void display_refresh(unsigned char newstate) {

+ 9 - 0
soft/display.h

@@ -12,7 +12,16 @@
 #define DISPLAY_STATE_COORD	9
 #define DISPLAY_STATE_ELE_SAT	10
 #define DISPLAY_STATE_MAIN_MENU	11
+#define DISPLAY_STATE_SETTINGS_MENU	12
 
+struct disp_s {
+	char line1[16];
+	char line2[17];
+};
+
+extern struct disp_s disp;
+
+void disp_init(void);
 void display_refresh(unsigned char newstate);
 void display_state(unsigned char newstate);
 

+ 56 - 50
soft/gpx.c

@@ -5,6 +5,7 @@
 #include "main.h"
 #include "gpx.h"
 #include "ff.h"
+#include "settings.h"
 
 #define KALMAN_Q	8.5e-6
 #define KALMAN_R	4e-5
@@ -109,62 +110,67 @@ void gpx_process_point(struct location_s *loc, FIL *file){
 	struct location_s *ptr;
 	struct location_s nloc;
 	
-	lat_est = kalman_predict(&kalman[0], loc->lat);
-	lon_est = kalman_predict(&kalman[1], loc->lon);
-	
-	lat_err = fabs(loc->lat - lat_est);
-	lon_err = fabs(loc->lon - lon_est);
-//	xprintf(PSTR("lat_err: %e, lon_err: %e, limit: %e\r\n"), lat_err, lon_err, (float)KALMAN_ERR_MAX);
-	if(lat_err > KALMAN_ERR_MAX || lon_err > KALMAN_ERR_MAX){
-		xputs_P(PSTR("KALMAN REJECT\r\n"));
-		return;
-	}
-	loc->lat = lat_est;
-	loc->lon = lon_est;
-	
-	prev_points_append(loc);
-	if(prev_points.count == PREV_POINTS_LENGTH){
-		float dist12 = distance(prev_points_get(0), prev_points_get(1));
-		float dist34 = distance(prev_points_get(2), prev_points_get(3));
-		float dist32 = distance(prev_points_get(2), prev_points_get(1));
-		xprintf(PSTR("New distance: %fm\r\n"), dist32);
-		if(dist34 > dist12 && dist32 > dist12){
-			xputs_P(PSTR("DISTANCE DIFF REJECT\r\n"));
+	if (get_flag(CONFFLAG_DISABLE_FILTERS)) {
+		xputs_P(PSTR("Write with filters disabled\r\n"));
+		gpx_write(loc, file);
+	} else {
+		lat_est = kalman_predict(&kalman[0], loc->lat);
+		lon_est = kalman_predict(&kalman[1], loc->lon);
+		
+		lat_err = fabs(loc->lat - lat_est);
+		lon_err = fabs(loc->lon - lon_est);
+	//	xprintf(PSTR("lat_err: %e, lon_err: %e, limit: %e\r\n"), lat_err, lon_err, (float)KALMAN_ERR_MAX);
+		if(lat_err > KALMAN_ERR_MAX || lon_err > KALMAN_ERR_MAX){
+			xputs_P(PSTR("KALMAN REJECT\r\n"));
 			return;
 		}
-		ptr = prev_points_get(PREV_POINTS_LENGTH - 2);
-	} else {
-		if(prev_points.count >= PREV_POINTS_LENGTH-2){
-			ptr = prev_points_get(prev_points.count - 2);
-			xputs_P(PSTR("NEW\r\n"));
+		loc->lat = lat_est;
+		loc->lon = lon_est;
+		
+		prev_points_append(loc);
+		if(prev_points.count == PREV_POINTS_LENGTH){
+			float dist12 = distance(prev_points_get(0), prev_points_get(1));
+			float dist34 = distance(prev_points_get(2), prev_points_get(3));
+			float dist32 = distance(prev_points_get(2), prev_points_get(1));
+			xprintf(PSTR("New distance: %fm\r\n"), dist32);
+			if(dist34 > dist12 && dist32 > dist12){
+				xputs_P(PSTR("DISTANCE DIFF REJECT\r\n"));
+				return;
+			}
+			ptr = prev_points_get(PREV_POINTS_LENGTH - 2);
 		} else {
-			return;
+			if(prev_points.count >= PREV_POINTS_LENGTH-2){
+				ptr = prev_points_get(prev_points.count - 2);
+				xputs_P(PSTR("NEW\r\n"));
+			} else {
+				return;
+			}
 		}
-	}
 
-	if(distance(&last_saved, ptr) < MIN_DIST_DELTA){
-		xputs_P(PSTR("Too small position change REJECT\r\n"));
-		return;
-	}
-
-	xputs_P(PSTR("ACCEPT\r\n"));
+		if(distance(&last_saved, ptr) < MIN_DIST_DELTA){
+			xputs_P(PSTR("Too small position change REJECT\r\n"));
+			return;
+		}
 
-	avg_store.lat += ptr->lat;
-	avg_store.lon += ptr->lon;
-	if(avg_count == AVG_COUNT/2)
-		avg_store.time = ptr->time;
-	
-	if(++avg_count == AVG_COUNT){
-		nloc.lat = avg_store.lat / AVG_COUNT;
-		nloc.lon = avg_store.lon / AVG_COUNT;
-		nloc.time = avg_store.time;
-		avg_count = 0;
-		avg_store.lat = 0;
-		avg_store.lon = 0;
-		avg_store.time = 0;
-		last_saved = nloc;
-		gpx_write(&nloc, file);
-		return;
+		xputs_P(PSTR("ACCEPT\r\n"));
+
+		avg_store.lat += ptr->lat;
+		avg_store.lon += ptr->lon;
+		if(avg_count == AVG_COUNT/2)
+			avg_store.time = ptr->time;
+		
+		if(++avg_count == AVG_COUNT){
+			nloc.lat = avg_store.lat / AVG_COUNT;
+			nloc.lon = avg_store.lon / AVG_COUNT;
+			nloc.time = avg_store.time;
+			avg_count = 0;
+			avg_store.lat = 0;
+			avg_store.lon = 0;
+			avg_store.time = 0;
+			last_saved = nloc;
+			gpx_write(&nloc, file);
+			return;
+		}
 	}
 }
 

+ 9 - 0
soft/main.c

@@ -27,6 +27,7 @@
 #include "working_modes.h"
 #include "timec.h"
 #include "nmea.h"
+#include "settings.h"
 
 /*FUSES = {0xFF, 0x11, 0xFE};*/		/* ATmega644PA fuses: Low, High, Extended.
 This is the fuse settings for this project. The fuse bits will be included
@@ -288,7 +289,9 @@ int main (void)
 	ioinit();
 	xdev_out(log_put);
 	xputs_P(PSTR("STARTUP\r\n"));
+	disp_init();
 	display_state(DISPLAY_STATE_STARTUP);
+	settings_load();
 	
 	for (;;) {
 		wdt_reset();
@@ -377,6 +380,10 @@ int main (void)
 						xprintf(PSTR("Temp: %.2f\r\n"), System.temperature);
 					else
 						xputs_P(PSTR("Temperature unknown\r\n"));
+					if (System.sbas)
+						xputs_P(PSTR("SBAS (DGPS) active\r\n"));
+					else
+						xputs_P(PSTR("SBAS inactive\r\n"));
 				}
 				LEDG_ON();
 				_delay_ms(2);
@@ -467,6 +474,8 @@ int main (void)
 		close_files(1);
 		if (System.status != STATUS_FILE_CLOSE_ERROR)
 			beep(500, 1);	/* Long beep on file close succeeded */
+		
+		settings_store(); /* save eeprom data */
 	}
 
 }

+ 6 - 3
soft/main.h

@@ -6,6 +6,7 @@
 #include <avr/interrupt.h>
 #include "stime.h"
 #include "expander.h"
+#include "settings.h"
 
 #define	IVT_SYNC	180			/* f_sync() interval (0:no periodic sync) [sec] */
 #define POWER_SW_TIME	300		/* power switch hold time to power off [10ms] */
@@ -130,16 +131,18 @@ struct timers {
 
 struct system_s {
 	struct timers timers;
+	struct config_s conf;
 	unsigned int global_error;
 	unsigned char status;
 	float bat_volt;
 	float temperature;
-	unsigned char temperature_ok;
-	unsigned char satellites_used;
 	unsigned char display_state;
-	unsigned char location_valid;
 	unsigned char keypress;
 	unsigned char working_mode;
+	unsigned temperature_ok:1;
+	unsigned satellites_used:5;
+	unsigned location_valid:2;
+	unsigned sbas:1;
 };
 
 struct location_s {

+ 6 - 0
soft/nmea.c

@@ -168,6 +168,12 @@ static void gp_gga_parse(const char *str) {
 	p = gp_col(str, 5); /* E/W */
 	if (*p != 'E')
 		location.lon = -location.lon;
+	
+	p = gp_col(str, 6); /* fix type */
+	if (*p == '2')
+		System.sbas = 1;
+	else
+		System.sbas = 0;
 
 	p = gp_col(str, 7); /* satellites used */
 	System.satellites_used = atoi(p);

+ 78 - 0
soft/settings.c

@@ -0,0 +1,78 @@
+#include <util/crc16.h>
+#include "main.h"
+#include "settings.h"
+#include "display.h"
+#include "xprintf.h"
+
+EEMEM struct config_s config_eep;
+EEMEM unsigned char config_crc;
+
+unsigned char settings_load(void) { /* 0 - ok, 1 - error */
+	unsigned char crc=0, rcrc, i;
+	unsigned char *cptr = (unsigned char *)&System.conf;
+	unsigned char ret;
+	eeprom_read_block(cptr, &config_eep, sizeof(struct config_s));
+	for (i=0; i<sizeof(struct config_s); i++) {
+		crc = _crc_ibutton_update(crc, cptr[i]);
+	}
+	rcrc = eeprom_read_byte(&config_crc);
+	crc = _crc_ibutton_update(crc, rcrc);
+	ret = check_config_data();
+	if (crc) {
+		xputs_P(PSTR("EEPROM read: bad CRC\r\n"));
+	} else if (ret) {
+		xputs_P(PSTR("EEPROM read: bad data\r\n"));
+	} else {
+		xputs_P(PSTR("EEPROM read OK\r\n"));
+	}
+	ret = ret || crc;
+	return ret;
+}
+
+unsigned char check_config_data(void) { /* 0 - ok, 1 - error */
+	return 0;
+}
+
+void settings_store(void) {
+	unsigned char i, crc=0;
+	unsigned char *cptr = (unsigned char *)&System.conf;
+	eeprom_update_block(cptr, &config_eep, sizeof(struct config_s));
+	for (i=0; i<sizeof(struct config_s); i++) {
+		crc = _crc_ibutton_update(crc, cptr[i]);
+	}
+	eeprom_update_byte(&config_crc, crc);
+	xputs_P(PSTR("EEPROM write done\r\n"));
+}
+
+void settings_display_and_modify_bool(unsigned char index, __flash const char *name, unsigned char k, unsigned char have_prev, unsigned char have_next) {
+	unsigned char val = get_flag(index);
+
+	if (k ==  K_LEFT || k ==  K_RIGHT) { /* change value */
+		set_flag(index, !val);
+	}
+
+	strcpy_P(disp.line1, name);
+	if (val)
+		strcpy_P(disp.line2, PSTR("< Tak > "));
+	else
+		strcpy_P(disp.line2, PSTR("< Nie > "));
+	strcat_P(disp.line2, have_next?PSTR(" \x01"):PSTR("  ")); /* down arrow */
+	strcat_P(disp.line2, have_prev?PSTR(" \x02"):PSTR("  ")); /* up arrow */
+}
+
+unsigned char get_flag(unsigned char index) {
+	volatile unsigned char *sptr = &System.conf.flags[index/8];
+	index %= 8;
+	unsigned char val = (*sptr) & _BV(index);
+	return val;
+}
+
+void set_flag(unsigned char index, unsigned char val) {
+	volatile unsigned char *sptr = &System.conf.flags[index/8];
+	index %= 8;
+	if (val)
+		*sptr |= _BV(index);
+	else
+		*sptr &= ~_BV(index);
+}
+

+ 24 - 0
soft/settings.h

@@ -0,0 +1,24 @@
+#pragma once
+#include <avr/eeprom.h>
+
+struct config_s {
+	union {
+		unsigned char conf_u8[16];
+		struct {
+			unsigned char __empty1;
+			unsigned char __empty2;
+		} u8;
+	};
+	unsigned char flags[4];
+};
+
+/* flags list */
+#define CONFFLAG_DISABLE_FILTERS	0
+
+unsigned char settings_load(void); /* 0 - ok, 1 - error */
+void settings_store(void);
+unsigned char check_config_data(void); /* 0 - ok, 1 - error */
+void settings_display_and_modify_bool(unsigned char index, __flash const char *name, unsigned char k, unsigned char have_prev, unsigned char have_next);
+unsigned char get_flag(unsigned char index);
+void set_flag(unsigned char index, unsigned char val);
+

+ 83 - 1
soft/working_modes.c

@@ -3,6 +3,7 @@
 #include "display.h"
 #include "HD44780-I2C.h"
 #include "xprintf.h"
+#include "settings.h"
 
 static signed char display_mode_index;
 
@@ -12,6 +13,31 @@ __flash const unsigned char main_display_modes[] = {
 	DISPLAY_STATE_ELE_SAT,
 };
 
+__flash const struct main_menu_pos_s main_menu[] = {
+	{
+		.func = enter_settings,
+	},
+};
+
+__flash const char _msg_disable_filters[] = "Nie filtruj";
+__flash const char _msg_back[] = "< Powrot";
+
+__flash const struct settings_menu_pos_s settings_menu[] = {
+	{
+		.type = SETTINGS_TYPE_BACK,
+		.name = _msg_back,
+	},
+	{
+		.type = SETTINGS_TYPE_BOOL,
+		.name = _msg_disable_filters,
+		.index = CONFFLAG_DISABLE_FILTERS,
+	},
+};
+
+#define SETTINGS_MENU_MAXPOS	((sizeof(settings_menu) / sizeof(settings_menu[0])) - 1)
+
+struct menu_params_s mp;
+
 void change_display_mode(signed char dir) {
 	display_mode_index += dir;
 	if (display_mode_index < 0)
@@ -39,18 +65,63 @@ unsigned char working_mode_main_menu(unsigned char k) {
 	switch (k) {
 		case K_LEFT:
 			return MODE_DEFAULT;
+		case K_RIGHT:
+			return main_menu_right_press();
+		case K_DOWN: /* TODO next menu item */
+		case K_UP: /* TODO prev menu item */
 	}
 	display_state(DISPLAY_STATE_MAIN_MENU);
 	return MODE_NO_CHANGE;
 }
 
+#define HAVE_NEXT_SETTING_POSITION (mp.settings_menu_pos < SETTINGS_MENU_MAXPOS)
+#define HAVE_PREV_SETTING_POSITION (mp.settings_menu_pos > 0)
+
+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:
+			if (settings_menu[mp.settings_menu_pos].type == SETTINGS_TYPE_BOOL)
+				settings_display_and_modify_bool(settings_menu[mp.settings_menu_pos].index, settings_menu[mp.settings_menu_pos].name, k, HAVE_PREV_SETTING_POSITION, HAVE_NEXT_SETTING_POSITION);
+			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_settings_menu_item(void) {
+	switch (settings_menu[mp.settings_menu_pos].type) {
+		case SETTINGS_TYPE_BOOL:
+			settings_display_and_modify_bool(settings_menu[mp.settings_menu_pos].index, settings_menu[mp.settings_menu_pos].name, 0, HAVE_PREV_SETTING_POSITION, HAVE_NEXT_SETTING_POSITION);
+			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;
+	};
+}
+
 unsigned char (*__flash const working_modes[])(unsigned char) = {
 	working_mode_default,
 	working_mode_main_menu,
+	working_mode_settings_menu,
 };
 
 void key_process(void) {
-//	static unsigned char mode_changed;
 	unsigned char k = getkey();
 	unsigned char newmode = working_modes[System.working_mode](k);
 	if (newmode != MODE_NO_CHANGE && newmode != System.working_mode) {
@@ -59,3 +130,14 @@ void key_process(void) {
 	}
 }
 
+unsigned char main_menu_right_press(void) {
+	if (main_menu[mp.main_menu_pos].func)
+		return main_menu[mp.main_menu_pos].func();
+	return MODE_NO_CHANGE;
+}
+
+unsigned char enter_settings(void) {
+	display_state(DISPLAY_STATE_SETTINGS_MENU);
+	return MODE_SETTINGS_MENU;
+}
+

+ 23 - 0
soft/working_modes.h

@@ -3,7 +3,30 @@
 #define MODE_NO_CHANGE	0xff
 #define MODE_DEFAULT	0
 #define MODE_MAIN_MENU	1
+#define MODE_SETTINGS_MENU	2
 
+#define SETTINGS_TYPE_BACK	0
+#define SETTINGS_TYPE_BOOL	1
+
+struct main_menu_pos_s {
+	unsigned char (* func)(void);
+};
+
+struct settings_menu_pos_s {
+	unsigned char type;
+	__flash const char *name;
+	unsigned char index;
+};
+
+struct menu_params_s {
+	unsigned char main_menu_pos;
+	unsigned char settings_menu_pos;
+};
+
+extern struct menu_params_s mp;
 
 void key_process(void);
+unsigned char main_menu_right_press(void);
+unsigned char enter_settings(void);
+void display_settings_menu_item(void);