#include <stdlib.h>
#include <unistd.h>
#include <asm/termios.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#define DEV "/dev/serial0"

int fd=0;

void inline setbaud(int baud)
{
	struct termios term;
	int result;

	if (fd) close(fd);
	if ((fd=open(DEV,O_RDWR))==-1) exit(1);

	usleep(200000);

	/* ponemos las cosas del puerto en su sitio */
	tcgetattr(fd,&term);

	term.c_cflag&=~CBAUD;
	term.c_cflag|=baud;
	term.c_cflag&=~CSIZE;
	term.c_cflag|=CS8;
	term.c_cflag|=CSTOPB;
	term.c_cflag&=~PARENB;
	
	term.c_lflag&=~ICANON;
	term.c_lflag&=~ECHO;
	term.c_lflag&=~ISIG;
	term.c_iflag&=~ICRNL;
	term.c_iflag&=~IXOFF;
	term.c_iflag&=~IXON; 
/*	term.c_cflag|=TIOCM_RI; */
	term.c_oflag&=~OPOST;
	
	if (tcsetattr(fd,TCSANOW,&term)) {
		fprintf(stderr,"Fallo en tcsetattr\n");
		exit(0);
	}


	/* Damos alimentación al cradle */

	result=0;
	result|=TIOCM_DTR;
	ioctl (fd, TIOCMBIS, &result);

	result=0;
	result|=TIOCM_RTS;
	ioctl (fd, TIOCMBIC, &result);
	
	usleep(200000);
	
}

#define FLAG	0x1C
#define ESC 	0x1B
#define FESC	0x1D

void send_byte(char dato)
{
	char cha[2];
	
	switch(dato){
	case FLAG:	cha[0]=ESC; cha[1]=FESC;
			write(fd,cha,2);
			break;
	case ESC:	cha[0]=cha[1]=ESC;
			write(fd,cha,2);
			break;
	default:	cha[0]=dato; write(fd,cha,1);
	}
}

void send_cmd(int cmd)
{
	static unsigned char buf[5]={0xff,0xff,0x7f,0x55,0x1c};
	write(fd,buf,5);
	send_byte(cmd);
}

void send_int(unsigned int dato)
{
	send_byte((dato>>24)&0xff);
	send_byte((dato>>16)&0xff);
	send_byte((dato>> 8)&0xff);
	send_byte((dato    )&0xff);
}

void prtuse(char *name,int dir)
{
	printf("\n\nUse: %s -u image.bin [address]	(Upload)\n",name);
	printf("     %s -x address		(Execute)\n",name);
	printf("     %s image.bin [address]	(Upload & Execute)\n",name);
	printf("     (Default address: 0x%08X)\n\n\n",dir);
	exit(0);
}

#define NBUF	8192

main(int argc,char **argv)
{
	unsigned char a,buf[NBUF];
	int i,j,k,n,fdi,d0,dir,op;
	char *fn,rotor[4]={'-','\\','|','/'};

	d0=dir=0x8C010000;
	
	if(argc<2) prtuse(argv[0],dir);
	if (strcmp(argv[1],"-u")==0) {
		op=1;
		if (argc>2) fn=argv[2]; else prtuse(argv[0],dir);
		if (argc>3) d0=dir=strtoul(argv[3],NULL,0);
	} else if (strcmp(argv[1],"-x")==0) {
		op=2;
		if (argc>2) d0=dir=strtoul(argv[2],NULL,0);
		else prtuse(argv[0],dir);
	} else {
		op=3;
		fn=argv[1];
		if (argc>2) d0=dir=strtoul(argv[2],NULL,0);
	}
	
	printf("Waiting for DC Synchro...\n");
	setbaud(B9600);
	do {
		send_cmd('S'); send_int(9600);
		setbaud(B9600);
		for(k=0;k<20;k++) {
			send_cmd('I');
			usleep(100000);
			i=fcntl(fd,F_GETFL);
			fcntl(fd,F_SETFL,i|O_NONBLOCK);
			j=read(fd,&a,1);
			fcntl(fd,F_SETFL,i);
			if (j>0 && a=='A') break;
			printf("\r%c",rotor[k&3]); fflush(stdout);
		}
		if (j && a=='A') printf("\r Alive 9600, OK\n");

		send_cmd('S'); send_int(115200);
		setbaud(B115200);
		for(k=0;k<20;k++) {
			send_cmd('I');
			usleep(100000);
			i=fcntl(fd,F_GETFL);
			fcntl(fd,F_SETFL,i|O_NONBLOCK);
			j=read(fd,&a,1);
			fcntl(fd,F_SETFL,i);
			if (j>0 && a=='A') break;
			printf("\r%c",rotor[k&3]); fflush(stdout);
		}
		if (j && a=='A') printf("\r Alive 115200, OK\n");
	}while(j==0 || a!='A');

	if (op&1) {
		if((fdi=open(fn,O_RDONLY))==-1) {perror("open"); exit(1);}
		printf("Loading at 0x%08X\n",d0);
		do {
			j=read(fdi,buf,NBUF);
			send_cmd('U'); send_int(dir); send_int(j);
			for(i=0;i<j;i++) send_byte(buf[i]);
			dir+=j;
			read(fd,&a,1);
			putchar(a); fflush(stdout);
		} while(j);
		close(fdi);
		printf("\n");
	}
	if (op&2) {
		printf("Executing at 0x%08X\n",d0);
		send_cmd('X');
		send_int(d0);
	}
}

