/*SRE.C*/
/************************************************************
 * Este programa faz a transferencia de arquivos atravé da  *
 * porta serial. Utiliza comunicação direta com a porta     *
 * serial por meio da programação do UART.                  *
 *                     MODO DE USO
                     = = = = = = = =
 * Deve ser instalado em dois computadores da seguinte      *
 * forma:                                                   *
 *        A linha de comando para o computador              *
 *        que receberá o arquivo é:                         *
 *               $> ./SRE R nomeArq.ext                     *
 *        A linha de comando para o computador              *
 *        que enviará o arquivo é:                          *
 *               $> ./SRE E nomeArq.ext                     *
 ***********************************************************/

#include <stdio.h>
#include <unistd.h>
#include <termios.h>

#define COM0 0x3f8     //para COM1, COM2 usar 0x2f8
#define VELOC 115200L  //bps
#define PARIDADE 0     //0=nenhuma, 1 = ímpar, 2=par
#define STOP 1         //1 stop bit
#define BITS_DADOS     //8 bits de dados
#define TRUE 1 
#define LSR COM0 + 5
#define LCR COM0 +3

void inicializa( unsigned int, long, int, int, int);
void recebeArq(char *);
void enviaArq(char *);

int kbhit(void) {
    int c ;

    tcsetattr(STDIN_FILENO,TCSANOW,&new_attr);
    c = getchar() ; /* retorna EOF se nada foi pressionado */
    tcsetattr(STDIN_FILENO,TCSANOW,&old_attr);

    return c ;
}

/* inicializa() */
/***************************************************
* Inicializa porta serial com os parâmetros        *
* enviados como argumentos                         *
***************************************************/
void inicializa(unsigned porta, 
			   long bps, //bits por segundo - taxa 
			             //de transmissão
				         //110, 150, 300, 600, 1200
				         //2400, 4800 ou 9600
			   int p, //paridade - 0=nenhuma
			          //1=ímpar, 2 = par
			   int stop, //1 ou dois stop bits 
			   int bitsDados){ //7 ou 8 bits de dados
	union{
		unsigned int nr;
		unigned char hilo[2];
	} divisor;
	unsigned char byteDeParam;
	
	int LCR=porta+3,
        DLL= porta,
        DLM=porta+1;
        //LSR=porta+5;

	//calcula o valor para ser enviado para registradores
	//de taxa de transmissão
	divisor.nr = (unsigned int) (1843200L/(bps*16L));
	
    //Liga bit (seta) do registrador de controle de caract. (LCR)
	//para permitir o acesso ao registradores da taxa de transmissão
	outportb(LCR,0x80); //0x80=1000.0000b

    //envia os dois bytes da taxa de transmissão para 
    //devidas portas
	//Byte menos significativo para porta 
	outportb(DLL, divisor.hilo[0]);//DLL
	//Byte mais significativo para porta
	outportb(DLM, divisor.hilo[1]);//DLM
	
    //Formata byte de parâmetro
    //0000.0011b é 8 bits de dados
               
	bitsDados -=5;   //8-5 = 3 = 0000.0011b   
	stop = (stop-1)<<2; ////manda para o bit 2, se stop == 1 stop << 4 == 0000.0100b
    
	if(p)//se 1 ou 2
		p=((p-1)<<4) | 0x08;  //(p-1)==1, (p-1)<< 4 == 0001.0000b
                              // 0001.0000b | 0000.1000b == 0001.1000b   
	
	//Envia byte de parâmetro para registrador de 
	//controle de linha
    byteDeParam = p | stop | bitsDados;//000.1000b | 0000.0100b | 0000.0011 = 0000.1111b
	outportb(LCR, byteDeParam);//LCR
}


/************************************************************
 * enviaArq()
 ************************************************************/ 
void enviaArq(char *nomeArq){
	FILE *f;
	unsigned int ch;
	int status, i=0;
	union{
		unsigned long arq;
		unsigned char byte[4];
	} tamanho;
	if((f=open(nomeArq,"rb"))==NULL){
		printf("\nNão posso abrir arquivo %s", nomeArq);
		exit();
	}
	//calcula o tamanho do arquivo a ser enviado
	fseek(f,0L,2);
	tamanho.arq =ftell(f);
	
	fseek(f,0L,0);//devolve o ponteiro ao início do arquivo
	
	//inicializa UART
	inicializa(COM0,VELOC, PARIDADE, STOP, BITS_DADOS);
	for(i=0;i<4;i++){ //envia tamanho do arquivo
		outportb(COM0, tamanho.byte[i]);
		
        status = inport(LSR);
		while(!(status & 1)) //aguarda sinal de pronto
			status = inportb(LSR);
		
		//dados disponíveis?
		ch=inportb(COM0); 
		if(ch!='*'){ //se sinal não identificado, receptor teve problema
			printf("\nErro na comunicação");
			exit(1);
		}	
	}
	while(ch=getc(f)!= (unsigned int)EOF) {
		outportb(COM0, ch); //envia caractere para receptor
		
		status = inportb(LSR); //Le do registrador LSR
		while(!(status & 1)) //aguarda sinal de pronto
			status = inportb(LSR);
	
		//dados disponíveis
		ch=inportb(COM0);
		if(ch!='*') { //se sinal não identificado, receptor teve problema
			printf("\nErro na comunicação");
			exit(1);
		}	
	}	
	fclose(f);
	exit(0);
	
}

/************************************************************
 * recebeArq()
 ************************************************************/ 

void recebeArq(char *nomeArq){
	int status;
	FILE *f;
	unsigned int ch=0;
	union{
		unsigned long arq;
		unsigned char byte[4];
	} tamanho;
	if((f=open(nomeArq,"rb"))==NULL){
		printf("\nNão posso abrir arquivo %s", nomeArq);
		exit(1);
	}
	
	//inicializa UART
	inicializa(COM0,VELOC, PARIDADE, STOP, BITS_DADOS);
	
	while(TRUE){ //
		status = inportb(LSR); //LSR
		if(!(status & 1)){ //se os dados estão disponíveis
			tamanho.byte[i++]=inportb(COM0); //recebe tamanho do arquivo
			outportb(COM0,'*'); //avisa transmissor que recebeu
			if(i==4) break;
		}
	}
	i=0L;
	while (i < tamanho.arq){ // tenta receber todos os bytes do arquivo

		status = inportb(LSR); 
		if(!(status & 1)){ //se os dados estão disponíveis
			ch=inportb(COM0);//recebe caractere
			putc(ch,f); //grava no arquivo
			outportb(COM0,'*'); //avisa transmissor que recebeu
			i++;
		}
	}
	fclose(f);
}

