1
0
Просмотр исходного кода

- Reduce max LFN length to save RAM
- Fix gpx data buffer overflow
- Add GPGGA parsing
- Update display system (WIP)
- Add universal uart.c module for both UARTs

k4be 2 лет назад
Родитель
Сommit
d4e5e9b364
12 измененных файлов с 489 добавлено и 444 удалено
  1. 1 1
      soft/Makefile
  2. 154 0
      soft/display.c
  3. 14 0
      soft/display.h
  4. 1 1
      soft/ffconf.h
  5. 8 7
      soft/gpx.c
  6. 89 138
      soft/main.c
  7. 6 1
      soft/main.h
  8. 153 0
      soft/uart.c
  9. 20 136
      soft/uart0.c
  10. 12 5
      soft/uart0.h
  11. 19 150
      soft/uart1.c
  12. 12 5
      soft/uart1.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
+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
 ASRC    = stime.S
 VPATH   =
 

+ 154 - 0
soft/display.c

@@ -0,0 +1,154 @@
+#include <avr/pgmspace.h>
+#include "main.h"
+#include "display.h"
+#include "HD44780-I2C.h"
+#include "xprintf.h"
+
+__flash const unsigned char battery_states[][8] = {
+	{
+		0b01110,
+		0b11111,
+		0b11111,
+		0b11111,
+		0b11111,
+		0b11111,
+		0b11111,
+		0b11111,
+	},
+	{
+		0b01110,
+		0b11111,
+		0b10001,
+		0b11111,
+		0b11111,
+		0b11111,
+		0b11111,
+		0b11111,
+	},
+	{
+		0b01110,
+		0b11111,
+		0b10001,
+		0b10001,
+		0b10001,
+		0b11111,
+		0b11111,
+		0b11111,
+	},
+	{
+		0b01110,
+		0b11111,
+		0b10001,
+		0b10001,
+		0b10001,
+		0b10001,
+		0b10001,
+		0b11111,
+	},
+};
+
+void battery_state_display(void) {
+	unsigned char i;
+	unsigned char index;
+	if (System.bat_volt > 4.0)
+		index = 0;
+	else if (System.bat_volt > 3.7)
+		index = 1;
+	else if (System.bat_volt > 3.4)
+		index = 2;
+	else
+		index = 3;
+	
+	LCD_WriteCommand(0x40 + 0); // 0x00
+
+	for(i=0; i<8; i++){
+		LCD_WriteData(battery_states[index][i]);
+	};
+}
+
+
+void display_refresh(unsigned char newstate) {
+	static const char *line1, *line2;
+	unsigned char changed = 0;
+	
+	switch (System.display_state) {
+		case DISPLAY_STATE_STARTUP:
+			line1 = PSTR("Uruchamianie...");
+			break;
+		case DISPLAY_STATE_POWEROFF_LOWBAT:
+			line2 = PSTR("Bateria slaba!");
+			/* fall through */
+		case DISPLAY_STATE_POWEROFF:
+			line1 = PSTR("Wylaczanie...");
+			break;
+		case DISPLAY_STATE_START_MESSAGE:
+			line1 = PSTR("Start");
+			switch(System.status){
+				case STATUS_NO_POWER: case STATUS_OK: case STATUS_NO_GPS: line2 = NULL; break;
+				case STATUS_NO_DISK:			line2 = PSTR("Brak karty!"); break;
+				case STATUS_DISK_ERROR:			line2 = PSTR("Blad karty!"); break;
+				case STATUS_FILE_WRITE_ERROR:	line2 = PSTR("Blad zapisu!"); break;
+				case STATUS_FILE_SYNC_ERROR:	line2 = PSTR("Blad zapisu FAT!"); break;
+				case STATUS_FILE_CLOSE_ERROR:	line2 = PSTR("Blad zamk.pliku!"); break;
+				case STATUS_FILE_OPEN_ERROR:	line2 = PSTR("Blad otw. pliku!"); break;
+			}
+			break;
+		case DISPLAY_STATE_CARD_OK:
+			line1 = PSTR("Karta OK!");
+			line2 = PSTR("Czekam na GPS...");
+			break;
+		case DISPLAY_STATE_FILE_OPEN:
+			line2 = PSTR("Zapis aktywny");
+			break;
+		case DISPLAY_STATE_FILE_CLOSED:
+			line2 = PSTR("Pliki zamkniete");
+			break;
+	}
+	if (newstate)
+		changed = 1;
+	if (timer_expired(lcd)) {
+		changed = 1;
+		set_timer(lcd, 1000);
+	}
+
+	/* write to LCD */
+	if (changed) {
+		battery_state_display();
+		unsigned char len;
+		LCD_GoTo(0,0);
+		if (line1) {
+			len = strlen_P(line1);
+			if (len > 15)
+				xprintf(PSTR("Warning: too long line1=%d, mem addr %4x\r\n"), (int)len, (unsigned int)line1);
+			LCD_WriteTextP(line1);
+			while (len<15) {
+				len++;
+				LCD_WriteData(' ');
+			}
+		} else {
+			for (len=0; len<15; len++)
+				LCD_WriteData(' ');
+		}
+		LCD_GoTo(0,1);
+		if (line2) {
+			len = strlen_P(line2);
+			if (len > 16)
+				xprintf(PSTR("Warning: too long line2=%d, mem addr %4x\r\n"), (int)len, (unsigned int)line1);
+			LCD_WriteTextP(line2);
+			while (len<16) {
+				len++;
+				LCD_WriteData(' ');
+			}
+		} else {
+			for (len=0; len<16; len++)
+				LCD_WriteData(' ');
+		}
+		LCD_GoTo(15, 0);
+		LCD_WriteData(0); /* battery symbol */
+	}
+}
+
+void display_state(unsigned char newstate) {
+	System.display_state = newstate;
+	display_refresh(newstate);
+}

+ 14 - 0
soft/display.h

@@ -0,0 +1,14 @@
+#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
+
+void display_refresh(unsigned char newstate);
+void display_state(unsigned char newstate);
+

+ 1 - 1
soft/ffconf.h

@@ -114,7 +114,7 @@
 
 
 #define FF_USE_LFN		1
-#define FF_MAX_LFN		255
+#define FF_MAX_LFN		63
 /* The FF_USE_LFN switches the support for LFN (long file name).
 /
 /   0: Disable LFN. FF_MAX_LFN has no effect.

+ 8 - 7
soft/gpx.c

@@ -10,8 +10,13 @@
 #define KALMAN_R	4e-5
 #define KALMAN_ERR_MAX	6e-4
 
+__flash const char xml_header[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+		"<gpx xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" version=\"1.1\" creator=\"k4be\">\n"
+		"\t<trk>\n"
+		"\t\t<trkseg>\n";
+
 FIL gpx_file;
-static char buf[256];
+static char buf[sizeof(xml_header)+1];
 
 struct kalman_s {
 	unsigned char initialized;
@@ -76,12 +81,8 @@ unsigned char gpx_init(FIL *file) {
 	last_saved.lon = 0;
 	last_saved.lat = 0;
 	last_saved.time = 0;
-	
-	strcpy_P(buf, PSTR("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-		"<gpx xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" version=\"1.1\" creator=\"k4be\">\n"
-		"\t<trk>\n"
-		"\t\t<trkseg>\n"
-	));
+
+	strcpy_P(buf, xml_header);
 	return f_write(file, buf, strlen(buf), &bw);
 }
 

+ 89 - 138
soft/main.c

@@ -10,6 +10,7 @@
 #include <avr/pgmspace.h>
 #include <avr/wdt.h>
 #include <string.h>
+#include <stdlib.h>
 #include "main.h"
 #include "ff.h"
 #include "diskio.h"
@@ -22,6 +23,7 @@
 #include "expander.h"
 #include "HD44780-I2C.h"
 #include "gpx.h"
+#include "display.h"
 
 
 /*FUSES = {0xFF, 0x11, 0xFE};*/		/* ATmega644PA fuses: Low, High, Extended.
@@ -42,7 +44,8 @@ void start_bootloader(void) {
 	typedef void (*do_reboot_t)(void);
 	const do_reboot_t do_reboot = (do_reboot_t)((FLASHEND - 1023) >> 1);
 	cli();
-	LCD_Clear();
+//	close_files(0); // FIXME not working
+	LCD_Clear(); /* Do not call display.c here! */
 	LCD_GoTo(0,0);
 	LCD_WriteTextP(PSTR("Aktualizacja"));
 	LCD_GoTo(8,1);
@@ -310,19 +313,9 @@ UINT gp_val3 (
 }
 
 
-
-
-static
-time_t gp_rmctime (	/* Get GPS status from RMC sentence */
-	const char *str
-)
-{
+static time_t gp_rmc_parse(const char *str) {
 	const char *p;
 	struct tm tmc;
-	double tmp;
-
-	if (gp_comp(str, PSTR("$GPRMC")))
-		return 0;	/* Not the RMC */
 
 	p = gp_col(str, 1);		/* Get h:m:s */
 	if (!p)
@@ -350,34 +343,64 @@ time_t gp_rmctime (	/* Get GPS status from RMC sentence */
 
 	FLAGS |= F_GPSOK;
 	
+	return utc;
+}
+
+static void gp_gga_parse(const char *str) {
+	const char *p;
+	double tmp;
+
+	/* check validity */
+	p = gp_col(str, 6);
+	if (*p == '0')
+		return;
+	
+	System.location_valid = 1;
+
 	/* parse location */
-	p = gp_col(str, 3);		/* latitude */
+	p = gp_col(str, 2);		/* latitude */
 	location.lat = gp_val2(p);	/* degrees */
 	p += 2;
 	xatof(&p, &tmp);	/* minutes */
 	tmp /= 60;			/* convert minutes to degrees */
 	location.lat += tmp;
 
-	p = gp_col(str, 4);	/* N/S */
+	p = gp_col(str, 3);	/* N/S */
 	if (*p != 'N')
 		location.lat = -location.lat;
 	
-	p = gp_col(str, 5);		/* longitude */
+	p = gp_col(str, 4);		/* longitude */
 	location.lon = gp_val3(p);	/* degrees */
 	p += 3;
 	xatof(&p, &tmp);	/* minutes */
 	tmp /= 60;			/* convert minutes to degrees */
 	location.lon += tmp;
 
-	p = gp_col(str, 6); /* E/W */
+	p = gp_col(str, 5); /* E/W */
 	if (*p != 'E')
 		location.lon = -location.lon;
 
-	location.time = utc;
+	p = gp_col(str, 7); /* satellites used */
+	System.satellites_used = atoi(p);
 	
-	return utc;
+	p = gp_col(str, 9); /* MSL altitude */
+	xatof(&p, &tmp);
+	location.alt = tmp;
+
+	location.time = utc; /* parsed from RMC */
 }
 
+static time_t gps_parse(const char *str) {	/* Get all required data from NMEA sentences */
+
+	if (!gp_comp(str, PSTR("$GPRMC"))) {
+		return gp_rmc_parse(str);
+	}
+	if (!gp_comp(str, PSTR("$GPGGA"))) {
+		gp_gga_parse(str);
+		return 0;
+	}
+	return 0;
+}
 
 #define LOG_SIZE	300
 
@@ -438,66 +461,23 @@ void ioinit (void)
 	ACSR = _BV(ACD);		/* Disable analog comp */
 }
 
-__flash const unsigned char battery_states[][8] = {
-	{
-		0b01110,
-		0b11111,
-		0b11111,
-		0b11111,
-		0b11111,
-		0b11111,
-		0b11111,
-		0b11111,
-	},
-	{
-		0b01110,
-		0b11111,
-		0b10001,
-		0b11111,
-		0b11111,
-		0b11111,
-		0b11111,
-		0b11111,
-	},
-	{
-		0b01110,
-		0b11111,
-		0b10001,
-		0b10001,
-		0b10001,
-		0b11111,
-		0b11111,
-		0b11111,
-	},
-	{
-		0b01110,
-		0b11111,
-		0b10001,
-		0b10001,
-		0b10001,
-		0b10001,
-		0b10001,
-		0b11111,
-	},
-};
-
-void battery_state_display(void) {
-	unsigned char i;
-	unsigned char index;
-	if (System.bat_volt > 4.0)
-		index = 0;
-	else if (System.bat_volt > 3.7)
-		index = 1;
-	else if (System.bat_volt > 3.4)
-		index = 2;
-	else
-		index = 3;
-	
-	LCD_WriteCommand(0x40 + 0); // 0x00
-
-	for(i=0; i<8; i++){
-		LCD_WriteData(battery_states[index][i]);
-	};
+void close_files(unsigned char flush_logs) {
+	UINT bw;
+	if (FLAGS & F_FILEOPEN) {
+		if (f_close(&gps_log))
+			System.status = STATUS_FILE_CLOSE_ERROR;
+		if (gpx_close(&gpx_file))
+			System.status = STATUS_FILE_CLOSE_ERROR;
+		if (flush_logs && logbuf.len && !f_write(&system_log, logbuf.buf, logbuf.len, &bw)) {
+			logbuf.len = 0;
+		}
+		if (f_close(&system_log))
+			System.status = STATUS_FILE_CLOSE_ERROR;
+		xputs_P(PSTR("File closed\r\n"));
+		display_state(DISPLAY_STATE_FILE_CLOSED);
+	}
+	FLAGS &= ~F_FILEOPEN;
+	disk_ioctl(0, CTRL_POWER, 0);
 }
 
 __flash const char __open_msg[] = "Open %s\r\n";
@@ -517,18 +497,15 @@ int main (void)
 	ioinit();
 	xdev_out(log_put);
 	xputs_P(PSTR("STARTUP\r\n"));
-	LCD_GoTo(0,0);
-	LCD_WriteTextP(PSTR("Uruchamianie... "));
+	display_state(DISPLAY_STATE_STARTUP);
 	
 	for (;;) {
 		wdt_reset();
 		if (FLAGS & (F_POWEROFF | F_LVD)) {
 			xputs_P(PSTR("POWEROFF\r\n"));
-			LCD_GoTo(0,0);
-			LCD_WriteTextP(PSTR("Wylaczanie...   "));
+			display_state(DISPLAY_STATE_POWEROFF);
 			if (FLAGS & F_LVD) {
-				LCD_GoTo(0,1);
-				LCD_WriteTextP(PSTR("Bateria slaba!  "));
+				display_state(DISPLAY_STATE_POWEROFF_LOWBAT);
 				_delay_ms(500);
 			}
 			POWEROFF();
@@ -539,19 +516,7 @@ int main (void)
 			xputs_P(PSTR("RESTART\r\n"));
 		}
 
-		LCD_GoTo(0,0);
-		LCD_WriteTextP(PSTR("Start           "));
-		LCD_GoTo(0,1);
-		switch(System.status){
-			case STATUS_NO_POWER: case STATUS_OK: case STATUS_NO_GPS: LCD_WriteTextP(PSTR("                ")); break;
-			case STATUS_NO_DISK:			LCD_WriteTextP(PSTR("Brak karty!     ")); break;
-			case STATUS_DISK_ERROR:			LCD_WriteTextP(PSTR("Blad karty!     ")); break;
-			case STATUS_FILE_WRITE_ERROR:	LCD_WriteTextP(PSTR("Blad zapisu!    ")); break;
-			case STATUS_FILE_SYNC_ERROR:	LCD_WriteTextP(PSTR("Blad zapisu FAT!")); break;
-			case STATUS_FILE_CLOSE_ERROR:	LCD_WriteTextP(PSTR("Blad zamk.pliku!")); break;
-			case STATUS_FILE_OPEN_ERROR:	LCD_WriteTextP(PSTR("Blad otw. pliku!")); break;
-		}
-
+		display_state(DISPLAY_STATE_START_MESSAGE);
 		xprintf(PSTR("LOOP err=%u\r\n"), (unsigned int)System.status);
 		utc = 0;
 		localtime = 0;
@@ -580,11 +545,7 @@ int main (void)
 		}
 		System.status = STATUS_NO_GPS;
 		xputs(PSTR("FS Ok\r\n"));
-		LCD_GoTo(0,0);
-		LCD_WriteTextP(PSTR("Karta OK!      "));
-		LCD_WriteData(0); /* battery symbol */
-		LCD_GoTo(0,1);
-		LCD_WriteTextP(PSTR("Czekam na GPS..."));
+		display_state(DISPLAY_STATE_CARD_OK);
 		beep(50, 1);				/* 1 beep */
 
 		/* Initialize GPS receiver */
@@ -596,7 +557,7 @@ int main (void)
 
 		for (;;) { /* main loop */
 			wdt_reset();
-			battery_state_display();
+			display_refresh(DISPLAY_STATE_NO_CHANGE);
 			gettemp();
 
 			if (!(FLAGS & F_GPSOK))
@@ -608,7 +569,7 @@ int main (void)
 				continue;
 			}
 
-			tmp_utc = gp_rmctime(Line);
+			tmp_utc = gps_parse(Line);
 			if (tmp_utc) {
 				localtime = tmp_utc + LOCALDIFF * 3600L;	/* Local time */
 				ct = *gmtime(&localtime);
@@ -626,6 +587,25 @@ int main (void)
 				LEDG_OFF();
 			}
 
+			if (FLAGS & F_FILEOPEN) {
+				f_write(&gps_log, Line, len, &bw);
+				if (bw != len) {
+					System.status = STATUS_FILE_WRITE_ERROR;
+					break;
+				}
+				if (System.location_valid) /* a new point */
+					gpx_process_point(&location, &gpx_file);
+				wdt_reset();
+				if (FLAGS & F_SYNC) {
+					if (f_sync(&gps_log)) {
+						System.status = STATUS_FILE_SYNC_ERROR;
+						break;
+					}
+					FLAGS &= ~F_SYNC;
+				}
+			}
+			System.location_valid = 0;
+
 			if (localtime && !(FLAGS & F_FILEOPEN)) {
 				xsprintf(Line, PSTR("%04u-%02u-%02u_%02u-%02u-%02u.LOG"), ct.tm_year+1900, ct.tm_mon + 1, ct.tm_mday, ct.tm_hour, ct.tm_min, ct.tm_sec);
 				xprintf(__open_msg, Line);
@@ -636,6 +616,7 @@ int main (void)
 					System.status = STATUS_FILE_OPEN_ERROR;
 					break;	/* Failed to start logging */
 				}
+				wdt_reset();
 
 				xsprintf(Line, PSTR("%04u-%02u-%02u_%02u-%02u-%02u.GPX"), ct.tm_year+1900, ct.tm_mon + 1, ct.tm_mday, ct.tm_hour, ct.tm_min, ct.tm_sec);
 				xprintf(__open_msg, Line);
@@ -647,6 +628,7 @@ int main (void)
 					System.status = STATUS_FILE_OPEN_ERROR;
 					break;	/* Failed to start logging */
 				}
+				wdt_reset();
 
 				xsprintf(Line, PSTR("%04u-%02u-%02u_%02u-%02u-%02u-SYSTEM.LOG"), ct.tm_year+1900, ct.tm_mon + 1, ct.tm_mday, ct.tm_hour, ct.tm_min, ct.tm_sec);
 				xprintf(__open_msg, Line);
@@ -659,30 +641,14 @@ int main (void)
 					System.status = STATUS_FILE_OPEN_ERROR;
 					break;	/* Failed to start logging */
 				}
+				wdt_reset();
 
 				FLAGS |= F_FILEOPEN;
 				System.status = STATUS_OK;
 				beep(50, 2);		/* Two beeps. Start logging. */
-				LCD_GoTo(0,1);
-				LCD_WriteTextP(PSTR("Zapis aktywny   "));
+				display_state(DISPLAY_STATE_FILE_OPEN);
 				continue;
 			}
-			if (FLAGS & F_FILEOPEN) {
-				f_write(&gps_log, Line, len, &bw);
-				if (bw != len) {
-					System.status = STATUS_FILE_WRITE_ERROR;
-					break;
-				}
-				if(tmp_utc) /* a new point */
-					gpx_process_point(&location, &gpx_file);
-				if (FLAGS & F_SYNC) {
-					if (f_sync(&gps_log)) {
-						System.status = STATUS_FILE_SYNC_ERROR;
-						break;
-					}
-					FLAGS &= ~F_SYNC;
-				}
-			}
 		}
 
 		/* Stop GPS receiver */
@@ -691,22 +657,7 @@ int main (void)
 		FLAGS &= ~F_POW;
 
 		/* Close file */
-		if (FLAGS & F_FILEOPEN) {
-			if (f_close(&gps_log))
-				System.status = STATUS_FILE_CLOSE_ERROR;
-			if (gpx_close(&gpx_file))
-				System.status = STATUS_FILE_CLOSE_ERROR;
-			if (logbuf.len && !f_write(&system_log, logbuf.buf, logbuf.len, &bw)) {
-				logbuf.len = 0;
-			}
-			if (f_close(&system_log))
-				System.status = STATUS_FILE_CLOSE_ERROR;
-			xputs_P(PSTR("File closed\r\n"));
-			LCD_GoTo(0,1);
-			LCD_WriteTextP(PSTR("Pliki zamkniete "));
-		}
-		FLAGS &= ~F_FILEOPEN;
-		disk_ioctl(0, CTRL_POWER, 0);
+		close_files(1);
 		if (System.status != STATUS_FILE_CLOSE_ERROR)
 			beep(500, 1);	/* Long beep on file close succeeded */
 	}

+ 6 - 1
soft/main.h

@@ -107,6 +107,7 @@ struct timers {
 	unsigned int beep;
 	unsigned int recv_timeout;
 	unsigned int system_log;
+	unsigned int lcd;
 };
 
 struct system_s {
@@ -116,9 +117,11 @@ struct system_s {
 	float bat_volt;
 	float temperature;
 	unsigned char temperature_ok;
+	unsigned char satellites_used;
+	unsigned char display_state;
+	unsigned char location_valid;
 };
 
-
 struct location_s {
 	float lon;
 	float lat;
@@ -152,4 +155,6 @@ static inline unsigned int atomic_get_uint(volatile unsigned int *volatile data)
 
 void disk_timerproc (void); /* mmc.h */
 const char *get_iso_time(time_t time);
+void close_files(unsigned char flush_logs);
+
 

+ 153 - 0
soft/uart.c

@@ -0,0 +1,153 @@
+/*---------------------------------------------------------*/
+/* UART functions for ATmega164A/PA/324A/PA/644A/PA/1284/P */
+/* #include-d by uart0.c and uart1.c                       */
+/*---------------------------------------------------------*/
+
+#if SZ_FIFO >= 256
+typedef uint16_t	idx_t;
+#else
+typedef uint8_t		idx_t;
+#endif
+
+
+typedef struct {
+	idx_t start, len;
+	uint8_t buff[SZ_FIFO];
+} FIFO;
+#if RECEIVE
+static
+volatile FIFO RxFifo;
+#endif
+
+#if USE_TXINT && TRANSMIT
+static
+volatile FIFO TxFifo;
+#endif
+
+static inline void fifo_add(volatile FIFO *fifo, char element) __attribute__((always_inline));
+static inline char fifo_get(volatile FIFO *fifo) __attribute__((always_inline));
+
+static inline void fifo_add(volatile FIFO *fifo, char element) {
+	unsigned char SREG_buf = SREG;
+	idx_t len = fifo->len;
+	cli();
+	idx_t idx = (fifo->start + len++) % SZ_FIFO;
+	fifo->buff[idx] = element;
+	if (len > SZ_FIFO) {
+		len--;
+		fifo->start = (fifo->start + 1) % SZ_FIFO;
+	}
+	fifo->len = len;
+	SREG = SREG_buf;
+}
+
+static inline char fifo_get(volatile FIFO *fifo) {
+	char ret = 0;
+	unsigned char SREG_buf = SREG;
+	idx_t start;
+	cli();
+	if (fifo->len > 0) {
+		start = fifo->start;
+		ret = fifo->buff[start];
+		fifo->start = (start + 1) % SZ_FIFO;
+		fifo->len--;
+	}
+	SREG = SREG_buf;
+	return ret;
+}
+
+/* Initialize UART */
+
+void _uart_init (void)
+{
+	_UCSRB = 0;
+
+	_PORT |= _BV(_TX); _DDR |= _BV(_TX);	/* Set TXD as output */
+	_DDR &= ~_BV(_RX); _PORT &= ~_BV(_RX); 	/* Set RXD as input */
+
+#if RECEIVE
+	RxFifo.len = 0;
+#endif
+#if USE_TXINT && TRANSMIT
+	TxFifo.len = 0;
+#endif
+
+	_UBRR = F_CPU / UART_BAUD / 16 - 1;
+#if RECEIVE && TRANSMIT
+	_UCSRB = _BV(_RXEN) | _BV(_RXCIE) | _BV(_TXEN);
+#elif TRANSMIT
+	_UCSRB = _BV(_TXEN);
+#elif RECEIVE
+	_UCSRB = _BV(_RXEN) | _BV(_RXCIE);
+
+#endif
+}
+
+
+/* Deinitialize UART */
+
+void _uart_deinit (void)
+{
+	_UCSRB = 0;
+}
+
+
+/* Get a received character */
+#if RECEIVE
+uint8_t _uart_test (void)
+{
+	return RxFifo.len > 0;
+}
+
+uint8_t _uart_get (void)
+{
+	return fifo_get(&RxFifo);
+}
+#endif
+
+/* Put a character to transmit */
+
+#if TRANSMIT
+void _uart_put (uint8_t d)
+{
+#if USE_TXINT
+	unsigned char SREG_buf;
+	idx_t len;
+	do {
+		SREG_buf = SREG;
+		cli();
+		len = TxFifo.len;
+		SREG = SREG_buf;
+	} while (len >= SZ_FIFO);
+	fifo_add(&TxFifo, d);
+	_UCSRB |= _BV(_UDRIE);
+#else
+	loop_until_bit_is_set(_UCSRA, _UDRE);
+	_UDR = d;
+#endif
+}
+#endif
+
+#if RECEIVE
+/* USART1 RXC interrupt */
+ISR(_USART_RX_vect)
+{
+	uint8_t d;
+
+	d = _UDR;
+	fifo_add(&RxFifo, d);
+}
+#endif
+
+
+#if TRANSMIT && USE_TXINT
+ISR(_USART_UDRE_vect)
+{
+	if (TxFifo.len)
+		_UDR = fifo_get(&TxFifo);
+	/* TxFifo.len is decremented by fifo_get */
+	if (!TxFifo.len)
+		_UCSRB &= ~_BV(_UDRIE);
+}
+#endif
+

+ 20 - 136
soft/uart0.c

@@ -2,146 +2,30 @@
 /* UART functions for ATmega164A/PA/324A/PA/644A/PA/1284/P */
 /*---------------------------------------------------------*/
 
-
 #include <avr/interrupt.h>
 #include "uart0.h"
 
-#define	UART0_BAUD		9600
+#define _PORT	PORTD
+#define _DDR	DDRD
+#define _RX		PD0
+#define _TX		PD1
+#define _UCSRA	UCSR0A
+#define _UCSRB	UCSR0B
+#define _UBRR	UBRR0
+#define _RXEN	RXEN0
+#define _RXCIE	RXCIE0
+#define _TXEN	TXEN0
+#define _UDRIE	UDRIE0
+#define _UDRE	UDRE0
+#define _UDR	UDR0
+#define _USART_RX_vect	USART0_RX_vect
+#define _USART_UDRE_vect	USART0_UDRE_vect
+
+#define	UART_BAUD		9600
 #define	USE_TXINT		0
 #define	SZ_FIFO			512
+#define RECEIVE			1
+#define TRANSMIT		0
 
+#include "uart.c"
 
-#if SZ_FIFO >= 256
-typedef uint16_t	idx_t;
-#else
-typedef uint8_t		idx_t;
-#endif
-
-
-typedef struct {
-	idx_t wi, ri, ct;
-	uint8_t buff[SZ_FIFO];
-} FIFO;
-static
-volatile FIFO RxFifo;
-#if USE_TXINT
-static
-volatile FIFO TxFifo;
-#endif
-
-
-
-/* Initialize UART */
-
-void uart0_init (void)
-{
-	UCSR0B = 0;
-
-	PORTD |= _BV(PD1); DDRD |= _BV(PD1);	/* Set TXD as output */
-	DDRD &= ~_BV(PD0); PORTD &= ~_BV(PD0); 	/* Set RXD as input */
-
-	RxFifo.ct = 0; RxFifo.ri = 0; RxFifo.wi = 0;
-#if USE_TXINT
-	TxFifo.ct = 0; TxFifo.ri = 0; TxFifo.wi = 0;
-#endif
-
-	UBRR0L = F_CPU / UART0_BAUD / 16 - 1;
-	UCSR0B = _BV(RXEN0) | _BV(RXCIE0) | _BV(TXEN0);
-}
-
-
-/* Deinitialize UART */
-
-void uart0_deinit (void)
-{
-	UCSR0B = 0;
-}
-
-
-/* Get a received character */
-
-uint8_t uart0_test (void)
-{
-	return RxFifo.ct;
-}
-
-
-uint8_t uart0_get (void)
-{
-	uint8_t d;
-	idx_t i;
-
-
-	do {
-		cli(); i = RxFifo.ct; sei();
-	} while (i == 0) ;
-	i = RxFifo.ri;
-	d = RxFifo.buff[i];
-	cli();
-	RxFifo.ct--;
-	sei();
-	RxFifo.ri = (i + 1) % sizeof RxFifo.buff;
-
-	return d;
-}
-
-
-/* Put a character to transmit */
-
-void uart0_put (uint8_t d)
-{
-#if USE_TXINT
-	idx_t i;
-
-	do {
-		cli(); i = TxFifo.ct; sei();
-	} while (i >= sizeof TxFifo.buff);
-	i = TxFifo.wi;
-	TxFifo.buff[i] = d;
-	TxFifo.wi = (i + 1) % sizeof TxFifo.buff;
-	cli();
-	TxFifo.ct++;
-	UCSR0B = _BV(RXEN0)|_BV(RXCIE0)|_BV(TXEN0)|_BV(UDRIE0);
-	sei();
-#else
-	loop_until_bit_is_set(UCSR0A, UDRE0);
-	UDR0 = d;
-#endif
-}
-
-
-/* USART0 RXC interrupt */
-ISR(USART0_RX_vect)
-{
-	uint8_t d;
-	idx_t i;
-
-
-	d = UDR0;
-	i = RxFifo.ct;
-	if (i < sizeof RxFifo.buff) {
-		RxFifo.ct = ++i;
-		i = RxFifo.wi;
-		RxFifo.buff[i] = d;
-		RxFifo.wi = (i + 1) % sizeof RxFifo.buff;
-	}
-}
-
-
-#if USE_TXINT
-ISR(USART0_UDRE_vect)
-{
-	idx_t n, i;
-
-
-	n = TxFifo.ct;
-	if (n) {
-		TxFifo.ct = --n;
-		i = TxFifo.ri;
-		UDR0 = TxFifo.buff[i];
-		TxFifo.ri = (i + 1) % sizeof TxFifo.buff;
-	}
-	if (n == 0)
-		UCSR0B = _BV(RXEN0)|_BV(RXCIE0)|_BV(TXEN0);
-}
-#endif

+ 12 - 5
soft/uart0.h

@@ -5,10 +5,17 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
 
-void uart0_init(void);		/* Initialize UART and Flush FIFOs */
-void uart0_deinit(void);		/* Deinitialize UART */
-uint8_t uart0_get (void);	/* Get a byte from UART Rx FIFO */
-uint8_t uart0_test(void);	/* Check number of data in UART Rx FIFO */
-void uart0_put (uint8_t);	/* Put a byte into UART Tx FIFO */
+#define _uart_init	uart0_init
+#define _uart_deinit	uart0_deinit
+#define _uart_get	uart0_get
+#define _uart_test	uart0_test
+#define _uart_put	uart0_put
+
+void _uart_init (void);		/* Initialize UART and Flush FIFOs */
+void _uart_deinit (void);		/* Deinitialize UART */
+uint8_t _uart_get (void);	/* Get a byte from UART Rx FIFO */
+uint8_t _uart_test (void);	/* Check number of data in UART Rx FIFO */
+void _uart_put (uint8_t);	/* Put a byte into UART Tx FIFO */
 
 #endif
+

+ 19 - 150
soft/uart1.c

@@ -2,161 +2,30 @@
 /* UART functions for ATmega164A/PA/324A/PA/644A/PA/1284/P */
 /*---------------------------------------------------------*/
 
-
 #include <avr/interrupt.h>
 #include "uart1.h"
 
-#define	UART1_BAUD		230400
+#define _PORT	PORTD
+#define _DDR	DDRD
+#define _RX		PD2
+#define _TX		PD3
+#define _UCSRA	UCSR1A
+#define _UCSRB	UCSR1B
+#define _UBRR	UBRR1
+#define _RXEN	RXEN1
+#define _RXCIE	RXCIE1
+#define _TXEN	TXEN1
+#define _UDRIE	UDRIE1
+#define _UDRE	UDRE1
+#define _UDR	UDR1
+#define _USART_RX_vect	USART1_RX_vect
+#define _USART_UDRE_vect	USART1_UDRE_vect
+
+#define	UART_BAUD		230400
 #define	USE_TXINT		1
 #define	SZ_FIFO			64
 #define RECEIVE			1
+#define TRANSMIT		1
 
-#if SZ_FIFO >= 256
-typedef uint16_t	idx_t;
-#else
-typedef uint8_t		idx_t;
-#endif
-
-
-typedef struct {
-	idx_t wi, ri, ct;
-	uint8_t buff[SZ_FIFO];
-} FIFO;
-#if RECEIVE
-static
-volatile FIFO RxFifo;
-#endif
-
-#if USE_TXINT
-static
-volatile FIFO TxFifo;
-#endif
-
-
-
-/* Initialize UART */
-
-void uart1_init (void)
-{
-	UCSR1B = 0;
-
-	PORTD |= _BV(PD3); DDRD |= _BV(PD3);	/* Set TXD as output */
-	DDRD &= ~_BV(PD2); PORTD &= ~_BV(PD2); 	/* Set RXD as input */
-
-#if RECEIVE
-	RxFifo.ct = 0; RxFifo.ri = 0; RxFifo.wi = 0;
-#endif
-#if USE_TXINT
-	TxFifo.ct = 0; TxFifo.ri = 0; TxFifo.wi = 0;
-#endif
-
-	UBRR1 = F_CPU / UART1_BAUD / 16 - 1;
-#if RECEIVE
-	UCSR1B = _BV(RXEN1) | _BV(RXCIE1) | _BV(TXEN1);
-#else
-	UCSR1B = _BV(TXEN1);
-#endif
-}
-
-
-/* Deinitialize UART */
-
-void uart1_deinit (void)
-{
-	UCSR1B = 0;
-}
-
-
-/* Get a received character */
-#if RECEIVE
-uint8_t uart1_test (void)
-{
-	return RxFifo.ct;
-}
-
-uint8_t uart1_get (void)
-{
-	uint8_t d;
-	idx_t i;
-	unsigned char SREG_buf = SREG;
-
-
-	do {
-		cli();
-		i = RxFifo.ct;
-		SREG = SREG_buf;
-	} while (i == 0) ;
-	i = RxFifo.ri;
-	d = RxFifo.buff[i];
-	cli();
-	RxFifo.ct--;
-	SREG = SREG_buf;
-	RxFifo.ri = (i + 1) % sizeof RxFifo.buff;
-
-	return d;
-}
-#endif
-
-
-/* Put a character to transmit */
-
-void uart1_put (uint8_t d)
-{
-#if USE_TXINT
-	idx_t i;
-	unsigned char SREG_buf = SREG;
-
-	do {
-		cli();
-		i = TxFifo.ct;
-		SREG = SREG_buf;
-	} while (i >= sizeof TxFifo.buff);
-	i = TxFifo.wi;
-	TxFifo.buff[i] = d;
-	TxFifo.wi = (i + 1) % sizeof TxFifo.buff;
-	cli();
-	TxFifo.ct++;
-	UCSR1B |= _BV(UDRIE1);
-	SREG = SREG_buf;
-#else
-	loop_until_bit_is_set(UCSR1A, UDRE1);
-	UDR1 = d;
-#endif
-}
-
-#if RECEIVE
-/* USART1 RXC interrupt */
-ISR(USART1_RX_vect)
-{
-	uint8_t d;
-	idx_t i;
-
-
-	d = UDR1;
-	i = RxFifo.ct;
-	if (i < sizeof RxFifo.buff) {
-		RxFifo.ct = ++i;
-		i = RxFifo.wi;
-		RxFifo.buff[i] = d;
-		RxFifo.wi = (i + 1) % sizeof RxFifo.buff;
-	}
-}
-#endif
-
-#if USE_TXINT
-ISR(USART1_UDRE_vect)
-{
-	idx_t n, i;
-
+#include "uart.c"
 
-	n = TxFifo.ct;
-	if (n) {
-		TxFifo.ct = --n;
-		i = TxFifo.ri;
-		UDR1 = TxFifo.buff[i];
-		TxFifo.ri = (i + 1) % sizeof TxFifo.buff;
-	}
-	if (n == 0)
-		UCSR1B &= ~_BV(UDRIE1);
-}
-#endif

+ 12 - 5
soft/uart1.h

@@ -5,10 +5,17 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
 
-void uart1_init(void);		/* Initialize UART and Flush FIFOs */
-void uart1_deinit(void);		/* Deinitialize UART */
-uint8_t uart1_get (void);	/* Get a byte from UART Rx FIFO */
-uint8_t uart1_test(void);	/* Check number of data in UART Rx FIFO */
-void uart1_put (uint8_t);	/* Put a byte into UART Tx FIFO */
+#define _uart_init	uart1_init
+#define _uart_deinit	uart1_deinit
+#define _uart_get	uart1_get
+#define _uart_test	uart1_test
+#define _uart_put	uart1_put
+
+void _uart_init (void);		/* Initialize UART and Flush FIFOs */
+void _uart_deinit (void);		/* Deinitialize UART */
+uint8_t _uart_get (void);	/* Get a byte from UART Rx FIFO */
+uint8_t _uart_test (void);	/* Check number of data in UART Rx FIFO */
+void _uart_put (uint8_t);	/* Put a byte into UART Tx FIFO */
 
 #endif
+