Index: trunk/software/firmware/main.c
===================================================================
--- trunk/software/firmware/main.c	(revision 8)
+++ trunk/software/firmware/main.c	(revision 11)
@@ -3,4 +3,5 @@
 #include <math.h> 
 #include <my_serial.h> 
+#include <my_serial2.h> 
 
 extern char stack; 
@@ -14,34 +15,65 @@
 static char counter_1hz;	       
 static volatile short counter_10hz;	       
-static volatile unsigned int softintrs;
-#define INT_10HZ	 0x0001
-#define INT_AD		 0x0002
-#define INT_DOAD	 0x0004
+static volatile unsigned char softintrs;
+#define INT_10HZ	 (unsigned char)0x01
+#define INT_AD		 (unsigned char)0x02
+#define INT_RX1		 (unsigned char)0x08
+#define INT_RX1OF	 (unsigned char)0x10
+
+static volatile unsigned char status;
+#define STAT_WAIT	(unsigned char)0x00
+#define STAT_MEASURE	(unsigned char)0x01
+#define STAT_EXIT	(unsigned char)0x02
+#define STAT_CONSOLE	(unsigned char)0x04
+
+static volatile unsigned char adstatus;
+#define ADSTAT_MEASURE	(unsigned char)0x01
+static unsigned char ad_resh;
+static unsigned char ad_resl;
+static unsigned char ad_channel;
+
 
 #define TIMER0_5MS 192 /* 48 without PLL */
 
 #define TIMER2_10HZ 1000
+
+#define LEDR LATAbits.LATA7
+#define LEDG LATAbits.LATA6
+#define PWRON LATCbits.LATC2
+#define RL1 LATCbits.LATC4
+#define RL2 LATCbits.LATC5
+#define SENSE PORTAbits.RA5
 
 #define CLRWDT __asm__("clrwdt")      
 #define SLEEP __asm__("sleep")      
 
-static char ad_channel;
-static long ad_i_result;
-static long ad_v_result;
-
+static void do_measure(void);
+static void do_console(void);
+static void do_cal_data(void);
+static void parse_rx(void);
+
+static char buf[84];
+
+/* address of calibration data in RAM */
+#define cal_data 0x01F000
+
+
+#if 1
 #define PRINTHEX(v) \
 	{ \
 		unsigned char c = (v); \
 		if (c < 10) { \
-			putchar('0' + c); \
+			uart_putchar_hard('0' + c); \
 		} else { \
-			putchar(('a' - 10) + c ); \
+			uart_putchar_hard(('a' - 10) + c ); \
 		} \
 	}
+#else
+#define PRINTHEX(v) {}
+#endif
 
 void
 main(void) __naked
 {
-	unsigned char c;
 	softintrs = 0;
 	counter_1hz = 10;
@@ -50,9 +82,14 @@
 	ANCON1 = 0x3f; /* an8-12 digital */
 
-	TRISCbits.TRISC1 = 0;
+	RL1 = 0;
+	TRISCbits.TRISC4 = 0;
+	RL2 = 0;
+	TRISCbits.TRISC5 = 0;
+	PWRON = 0;
 	TRISCbits.TRISC2 = 0;
-	PORTCbits.RC1 = 0;
-	PORTCbits.RC2 = 0;
-
+	LEDR = 1;
+	TRISAbits.TRISA7 = 0;
+	LEDG = 0;
+	TRISAbits.TRISA6 = 0;
 
 	/* switch PLL on */
@@ -91,5 +128,27 @@
 	SPBRG1 = 12;
 
+	/* pre-configure UART2 */
+	/* turn off PPS write protect */
+	__asm
+	banksel _PPSCON
+	movlw   0x55
+	movwf   _EECON2, a
+	movlw   0xAA
+	movwf   _EECON2, a 
+	BCF     _PPSCON, _IOLOCK, b
+	__endasm;
+
+	TRISCbits.TRISC0 = 1;
+	LATCbits.LATC1 = 1;
+	TRISCbits.TRISC1 = 0;
+	RPINR16 = 11; /* RC0 = RX */
+	RPOR12 = 6; /* RC1 = TX */
+	TXSTA2 = 0x24; /* TXEN, BRGH set, others clear */
+	RCSTA2 = 0x90; /* UART enable, receiver disabled */
+	BAUDCON2 = 0x08; /* BRG16 */
+
 	USART_INIT(0);
+	USART2_INIT(0);
+
 	stdout = STREAM_USER; /* Use the macro PUTCHAR with printf */
 
@@ -115,4 +174,6 @@
 	PIE1bits.TMR2IE = 1;
 
+	status = STAT_WAIT;
+	adstatus = 0;
 
 	INTCONbits.GIE_GIEH=1;  /* enable high-priority interrupts */   
@@ -143,62 +204,28 @@
 	/* enable watch dog timer */  
 	WDTCON = 0x01;
+	LEDR = 0;
 
 	printf("\nready\n");
-	/* start I calibration process */
 	ad_channel = 0;
 	ADCON0bits.CHS = 0;
-	softintrs &= ~INT_DOAD;
-	PORTCbits.RC1 = 1;
-	PORTCbits.RC2 = 0;
-
-again:
-	while (1) {
+	LEDG = 1;
+	PWRON = 0;
+
+	while ((status & STAT_EXIT) == 0) {
 		CLRWDT;
-		if (softintrs & INT_AD) {
-			softintrs &= ~INT_AD;
-			if (ad_channel == 0) {
-				PRINTHEX(PORTB & 0xf);
-				PRINTHEX(ADRESH & 0xf);
-				PRINTHEX(ADRESL >> 4);
-				PRINTHEX(ADRESL & 0xf);
-
-				//printf("%1x%3x", (PORTB & 0xf), ADRESL | (ADRESH << 8));
-				/*
-				 * needs 2Tac, or 32 instrutions
-				 * before next sample. assume we
-				 * already have them since the
-				 * interrupt
-				 */
-				ad_channel = 1;
-				ADCON0bits.CHS = 1;
-			} else {
-				ad_channel = 0;
-				ADCON0bits.CHS = 0;
-				PRINTHEX(ADRESH & 0xf);
-				PRINTHEX(ADRESL >> 4);
-				PRINTHEX(ADRESL & 0xf);
-				putchar('X');
-				//printf("%3xX", ADRESL | (ADRESH << 8));
-			}
-		}
-
-		if ((softintrs & INT_AD) == 0 &&
-	            (softintrs & INT_DOAD) && 
-		    ADCON0bits.GO_NOT_DONE == 0) {
-			ADCON0bits.GO_NOT_DONE = 1;
-			softintrs &= ~INT_DOAD;
-		}
-
-		if (RCREG1 == 'r')
-			break;
-		SLEEP;
-
-	}
-
-end:
-
-	while ((c = getchar()) != 'r') {
-		printf("got %c\n", c);
-		goto again;
+		if (softintrs & INT_10HZ) {
+			softintrs &= ~INT_10HZ;
+			LEDG ^= 1;
+		}
+		if (softintrs & INT_RX1) {
+			parse_rx();
+		} else {
+			SLEEP;
+			continue;
+		}
+		if (status & STAT_MEASURE)
+			do_measure();
+		else if (status & STAT_CONSOLE)
+			do_console();
 	}
 	printf("returning\n");
@@ -209,5 +236,311 @@
 }
 
-unsigned int
+static void
+parse_rx()
+{
+	char c;
+	char c2;
+	char ok = 1;
+	char err = 0;
+	long br;
+	short brgreg = 0;
+
+	softintrs &= ~INT_RX1;
+	c = uart_getchar();
+	switch(c) {
+	case 'B':
+		c = uart_getchar();
+		br = 0;
+		while(c != '\n') {
+			if (c < '0' || c > '9') {
+				err = 1;
+				break;
+			}
+			br = br * 10 + c - '0';
+			c = uart_getchar();
+		}
+		if (br > 0) {
+			/*
+			 * brg = F / 16 / (n + 1)
+			 * brg * (n + 1) = F / 16
+			 * n + 1 = F / 16 / brg
+			 * n = F / 16 / brg - 1
+			 * with F = 48Mhz
+			 * n = 3000000 / brg - 1
+			 */
+			brgreg = (12000000L + br / 2) / br - 1;
+			printf("brgreg %d\n", brgreg);
+		}
+		if (err == 0) {
+			if (br > 0) {
+				SPBRGH2 = (brgreg >> 8);
+				SPBRG2 = (brgreg & 0xff);
+			}
+			status = STAT_CONSOLE;
+		}
+		break;
+	case 'C':
+		do_cal_data();
+		c = '\n';
+		break;
+	case 'E':
+		status = STAT_EXIT;
+		break;
+	case 'M':
+		c = uart_getchar();
+		if (c == '0') {
+			if (status == STAT_MEASURE)
+				ok = 0;
+			status = STAT_WAIT;
+		} else if (c == '1') {
+			status = STAT_MEASURE;
+		} else {
+			err = 1;
+		}
+		break;
+	case 'P':
+		c = uart_getchar();
+		if (c == '0')
+			PWRON = 0;
+		else if (c == '1')
+			PWRON = 1;
+		else
+			err = 1;
+		break;
+	case 'R':
+		c = uart_getchar();
+		if (c != '\n') {
+			c2 = uart_getchar();
+			if (c == '1') {
+				if (c2 == '0')
+					RL1 = 0;
+				else if (c2 == '1')
+					RL1 = 1;
+				else
+					err = 1;
+			} else if (c == '2') {
+				if (c2 == '0')
+					RL2 = 0;
+				else if (c2 == '1')
+					RL2 = 1;
+				else
+					err = 1;
+			} else {
+				err = 1;
+			}
+			c = c2;
+		}
+		break;
+	case 'S':
+		printf("power %s RL %s %s SENSE %s GPIO 0x%x\n",
+		    PWRON ? "on" : "off",
+		    RL1 ? "on" : "off",
+		    RL2 ? "on" : "off",
+		    SENSE ? "off" : "on",
+		    PORTB);
+		break;
+	default:
+		err = 1;
+		break;
+	}
+	while (c != '\n')
+		c = uart_getchar();
+	if (err)
+		printf("\nERROR\n");
+	else if (ok)
+		printf("\nOK\n");
+
+	if (softintrs & INT_RX1OF) {
+		PIE1bits.RC1IE = 0;
+		softintrs &= ~INT_RX1OF;
+		softintrs &= ~INT_RX1;
+		uart_rxbuf_prod = uart_rxbuf_cons = 0;
+		PIE1bits.RC1IE = 1;
+	}
+}
+
+static void
+printhex(unsigned char c) __wparam __naked
+{
+	(void)c;
+	__asm
+	andlw 0x0f;
+	sublw 9;
+	bc decimal;
+	sublw '@';
+	goto _uart_putchar_hard;
+decimal:
+	sublw '9';
+	goto _uart_putchar_hard;
+	__endasm;
+}
+
+static void
+do_measure()
+{
+	softintrs &= ~INT_AD;
+	adstatus = ADSTAT_MEASURE;
+	ADCON0bits.CHS = 0;
+
+	LEDR = 0;
+	LEDG = 1;
+	UART_FLUSH();
+	uart_putchar_hard('X');
+	while (status & STAT_MEASURE) {
+		CLRWDT;
+		if (softintrs & INT_AD) {
+			if (ad_channel == 0) {
+				printhex(PORTB >> 4);
+				printhex(PORTB);
+				printhex(ad_resh);
+				printhex(ad_resl >> 4);
+				printhex(ad_resl);
+			} else {
+				printhex(ad_resh);
+				printhex(ad_resl >> 4);
+				printhex(ad_resl);
+				uart_putchar_hard('X');
+			}
+			softintrs &= ~INT_AD;
+		}
+		if (softintrs & INT_RX1) {
+			parse_rx();
+		} else {
+			SLEEP;
+		}
+	}
+	adstatus = 0;
+	printf("\nOK\n");
+}
+
+static void
+do_console()
+{
+	char previous_rx1 = 0;
+	char c;
+	char more_work = 0;
+
+	printf("connecting to console - exit with #.\n");
+	/* clear buffer */
+	PIE3bits.RC2IE = 0;
+	uart2_rxbuf_prod = uart2_rxbuf_cons = 0;
+	PIE3bits.RC2IE = 1;
+	RCSTA2bits.SPEN = 1;
+	while ((status & STAT_CONSOLE) || more_work) {
+		CLRWDT;
+		more_work = 0;
+		if (softintrs & INT_10HZ) {
+			softintrs &= ~INT_10HZ;
+			LEDG ^= 1;
+		}
+		if (uart_rxbuf_cons != uart_rxbuf_prod) {
+			c = uart_getchar();
+			/*
+			 * #. exits console mode
+			 * ## sends #
+			 * anything else send both char unmodified
+			 */
+			if (previous_rx1 == '#') {
+				if (c == '.') {
+					status = STAT_WAIT;
+				} else if (c == '#') {
+					uart2_putchar_raw(c);
+				} else {
+					uart2_putchar_raw(previous_rx1);
+					uart2_putchar_raw(c);
+				}
+			} else {
+				uart2_putchar_raw(c);
+			}
+			previous_rx1 = c;
+			more_work = 1;
+		}
+		if (uart2_rxbuf_cons != uart2_rxbuf_prod) {
+			c = uart2_getchar();
+			uart_putchar_raw(c);
+			more_work = 1;
+		}
+		if (more_work == 0 && (status & STAT_CONSOLE))
+			SLEEP;
+	}
+	RCSTA2bits.SPEN = 0;
+	printf("exit from console\n");
+}
+
+static void
+do_write(void)
+{
+	EECON2 = 0x55;
+	EECON2 = 0xaa;
+	EECON1bits.WR = 1;
+	while (EECON1bits.WR)
+		; /* wait */
+}
+
+static void
+do_cal_data()
+{
+	char i = 0;
+	char err = 0;
+	char c;
+
+	c = uart_getchar();
+	while (c != '\n') {
+		if ((c < '0' || c > '9') && c != ' ' && c != '.') {
+			printf("cal error at %c (%d)\n", c, i);
+			err = 1;
+		}
+		if (i > 82) {
+			printf("cal error at %c (%d)\n", c, i);
+			err = 1;
+		} else {
+			buf[i] = c;
+			i++;
+		}
+		c = uart_getchar();
+	}
+	if (err == 0 && i != 0 && i != 83) {
+		printf("cal error: %d\n", i);
+	} else if (err == 0 && i != 0) {
+		/* erase 1k block */
+		INTCONbits.GIE_GIEH=0; /* disable interrupts */
+		INTCONbits.PEIE_GIEL=0;
+		TBLPTRU = ((long)cal_data >> 16) & 0xff;
+		TBLPTRH = ((long)cal_data >> 8) & 0xff;
+		TBLPTRL = (long)cal_data & 0xff;
+		EECON1 = 0x14; /* enable write+erase */
+		do_write();
+		EECON1 = 0x00; /* disable write */
+		for (i = 0; i < 83; i++) {
+			TABLAT = buf[i];
+			__asm__("tblwt*+");
+			if (i == 63) {
+				__asm__("tblrd*-");
+				EECON1 = 0x04; /* enable write */
+				do_write();
+				EECON1 = 0x00; /* disable write */
+				__asm__("tblrd*+");
+			}
+		}
+		__asm__("tblrd*-");
+		EECON1 = 0x04; /* enable write */
+		do_write();
+		EECON1 = 0x00; /* disable write */
+		INTCONbits.PEIE_GIEL=1;
+		INTCONbits.GIE_GIEH=1; /* enable interrupts */
+	}
+	printf("cal_data ");
+	TBLPTRU = ((long)cal_data >> 16) & 0xff;
+	TBLPTRH = ((long)cal_data >> 8) & 0xff;
+	TBLPTRL = (long)cal_data & 0xff;
+	EECON1 = 0x00; /* disable writes */
+	for (i = 0; i < 83; i++) {
+		__asm__("tblrd*+");
+		putchar(TABLAT);
+	}
+	printf("\n");
+}
+
+unsigned short
 timer0_read() __naked   
 {
@@ -267,5 +600,4 @@
 	 * so we have to be carefull with C code !
 	 */
-#if 0
 	counter_10hz--;
 	if (counter_10hz == 0) {
@@ -273,9 +605,10 @@
 		softintrs |= INT_10HZ;
 	}			     
-#endif
-	if (softintrs & INT_DOAD) {
-		PORTCbits.RC2=1;
-	}
-	softintrs |= INT_DOAD;
+	if (adstatus & ADSTAT_MEASURE) {
+		if (PIR1bits.ADIF) {
+			LEDR = 1;
+		}
+		ADCON0bits.GO_NOT_DONE = 1;
+	}
 	__asm
 	retfie 1
@@ -287,5 +620,21 @@
 {
 	USART_INTR;
+	USART2_INTR;
 	if (PIE1bits.ADIE && PIR1bits.ADIF) {
+		if (softintrs & INT_AD) {
+			LEDR = 1;
+		}
+		ad_channel = ADCON0bits.CHS;
+		ad_resl = ADRESL;
+		ad_resh = ADRESH;
+		/*
+		 * needs 2Tac, or 32 instrutions
+		 * before next sample. assume we'll
+		 * have them at timer2 interrupt
+		 */
+		if (ad_channel == 0)
+			ADCON0bits.CHS = 1;
+		else
+			ADCON0bits.CHS = 0;
 		PIR1bits.ADIF = 0;
 		softintrs |= INT_AD;
