#include <18F2480.h>
#device ADC=10
#device *=16
#include <string.h>
#FUSES H4,NOPROTECT,PUT,NOLVP,BROWNOUT,NOWDT
#use delay(clock=16000000)
#use rs232(baud=57600,xmit=PIN_C6,rcv=PIN_C7)	

#use standard_io(A)
#use standard_io(B)
#use standard_io(C)

#include "can-18xxx8.h"
#include "can-18xxx8.c"

#include <stdlib.h>
#include <input.c>

typedef struct {
	signed int16 adc[8];
} record;
record current;
record last;

/* map actual ADC channel to channel on DB-25 */
int8 const adc_channels[8]={0,1,2,3,4,8,9,10};
int8 const adc_order[8]   ={7,6,5,4,3,2,1,0};

/* CAN id's for the 8 ADC channels */
int16 adc_can_id[8];
int8 adc_can_hysteresis[8];

unsigned long millisecond_count;
unsigned long send_count;
unsigned long send_delay;
short do_send;

#rom 0xF00000 = { 	0xfa00, 0x3412, 0x0000, 0x0000, 0x0000,\ 
							0x0000, 0x0000, 0x0000, 0x0000,\
					0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }

void init_adc(void) {
	setup_adc( ADC_CLOCK_INTERNAL );
	setup_adc_ports(ALL_ANALOG);
}

void adc_read_all(void) {
	int i;

	for ( i=0 ; i<8 ; i++ ) {
		set_adc_channel(adc_channels[i]);	
		current.adc[adc_order[i]]=read_adc();
	}
}

void setScanRate(void) {
	signed long l;

setScanRateAgain:
	printf("\r\nCurrent sampling delay is %ld milliseconds.\r\n",send_delay);
	puts("Enter sampling delay in milliseconds: ");
	l=get_long();

	send_delay=l;	
}

void setCanChannel(void) {
	int i, ch;
	int8 a,b;
	int16 l;
	
selectChan:
	puts("\r\nSelect a channel:");
	for ( i=0 ; i<8 ; i++ ) {
		if ( 0 != adc_can_id[i] ) {
			printf("Channel %d transmit enabled, ID is 0x%Lx, hysteresis is %d\r\n",i,adc_can_id[i],adc_can_hysteresis[i]);
 		} else {
			printf("Channel %d transmit disabled.\r\n",i);
		}
	}

	ch=get_int();
	if ( ch>7 ) {
		puts("\r\nInvalid channel. Try again.");
		goto selectChan;
	}

setCanID:	
	puts("\r\nEnter desired CAN id. To disable a channel from ");
	puts("transmitting CAN message set its ID to be 0.");
	
	a=gethex();
	b=gethex();

	l=make16(a,b);
	if ( 0 != l && i!=ch ) {
		for ( i=0 ; i<8 ; i++ ) {
			if ( adc_can_id[i] == l ) {
				puts("\r\nThere is already a channel with that ID; try again!\r\n"); 
				goto setCanID;
			}
		}
	}
	adc_can_id[ch]=l;

	printf("\r\nChannel %d ID is 0x%Lx\r\n",ch,adc_can_id[ch]);

	puts("Send when change between readings is:");
	i=get_int();
	write_eeprom(18+ch,i);
	adc_can_hysteresis[ch]=i;
	printf("\r\nHysteresis for channel %d is %d\r\n",ch,adc_can_hysteresis[ch]);

}

int16 read_eeprom16(int8 address) {
	int8 a,b;

	a=read_eeprom(address);
	b=read_eeprom(address+1);

	return make16(a,b);
}

void write_eeprom16(int8 address, int16 value) {
	write_eeprom(address,make8(value,1));
	write_eeprom(address+1,make8(value,0));
}
void write_config(void) {
	int i,j;

	/* write configuration to EEPROM */
	puts("\r\n# writing configuration to eeprom");
	write_eeprom16(0,send_delay);
	for ( i=0,j=2 ; i<8 ; i++,j+=2 ) {
		write_eeprom16(j,adc_can_id[i]);
	}
	/* read the hysteresis values */
	for ( i=0,j=18 ; i<8 ; i++,j++ ) {
		write_eeprom(j,adc_can_hysteresis[i]);
	}

}

void read_config(void) {
	int i,j;

	puts("# reading configuration from eeprom");
	send_delay = read_eeprom16(0);
	printf("# send delay: %lu\r\n",send_delay);

	/* read the adc can id */
	for ( i=0,j=2 ; i<8 ; i++,j+=2 ) {
		adc_can_id[i] = read_eeprom16(j);
		printf("# adc_can_id[%d]=0x%Lx\r\n",i,adc_can_id[i]);
	}
	/* read the hysteresis values */
	for ( i=0,j=18 ; i<8 ; i++,j++ ) {
		adc_can_hysteresis[i]=read_eeprom(j);
		printf("# adc_can_hysteresis[%d]=%d\r\n",i,adc_can_hysteresis[i]);
	}

}

#int_rda
void serial_isr() {

	/* swallow the character that got us in here */
	getchar();

	/* this kicks us into configuration mode */
	disable_interrupts(INT_RDA);

	puts("# entering configuration mode");
menu:
	puts("1) Set sampling delay");
	puts("2) Set channel parameters (to sample, CAN ID)");
	puts("3) Done");

	switch ( get_int() ) {
		case 1:	setScanRate();
				break;
		case 2: setCanChannel();
				break;
		case 3:
				write_config();
				puts("");
				return;
		default:
				goto menu;
	}

	puts("");
	goto menu;	

}

#int_timer2
void int_ms_isr(void) {
	/* we get called every millisecond */
	millisecond_count++;
	send_count++;

	if ( send_count==send_delay ) {
		do_send=1;
		send_count=0;
	}

	if ( millisecond_count==999 ) {
		millisecond_count=0;
	}
}

void main(void) {
	int i;
	int16 l;

	puts("# canadc startup");
	printf("# firmware compiled %s\r\n",__DATE__);

	millisecond_count=0;
	do_send=0;

	read_config();


	if ( 0==send_delay || 0xffff==send_delay ) {
		send_delay=500;
	}

	init_adc();

	puts("# press any key in the next two seconds to enter config mode");

	/* check to see if we should go into configuration mode */
	enable_interrupts(INT_RDA);
	enable_interrupts(GLOBAL);
	delay_ms(2000);
	disable_interrupts(INT_RDA);


	/* start millisecond timer */
	setup_timer_2(T2_DIV_BY_4,249,1); // Set 1mS period with 4MHz crystal
	enable_interrupts(INT_TIMER2);

	puts("# initializing CAN controller");
	/* Setup CAN controller so we can send messages */
	can_init();
	
	puts("# starting loop");
	while (1) {
		adc_read_all();	

		if ( 1==do_send ) {
//			can_putd(0x12345678,buff,strlen(buff),0,FALSE,FALSE);



			for ( i=0 ; i<8 ; i++ ) {
				if ( 7 != i ) 
					printf("%04ld,",current.adc[i]);
				else
					printf("%04ld\r\n",current.adc[i]);



				if ( 0 != adc_can_id[i] ) {
					/* check to see if we have changed */
					if ( abs(last.adc[i]-current.adc[i]) > adc_can_hysteresis[i] ) {
						/* convert to little endian */
						l = make16(make8(current.adc[i],0),make8(current.adc[i],1));
						/* send CAN message */
						can_putd(adc_can_id[i],&l,2,0,FALSE,FALSE);
						// can_putd(adc_can_id[i],&current.adc[i],2,0,FALSE,FALSE);
						//printf("---> sent CAN message for channel %d\r\n",i);
					}
				}
				last.adc[i]=current.adc[i];
			}
			do_send=0;
		}


	}

	/* give us a break point */
	delay_cycles(1);
}
