#include <system.h>
# pragma CLOCK_FREQ 20000000

void receptieSeriala(void);
void transmisieSeriala(void);
void tmr1(void);
void tmr0(void);
void timeBaseTmr2(void);

//variabile globale:
char eroareReceptie,ctrlReceptie,ctrlTransmisie,startStopFrecv,transmisieQueue,startStopGenSemnal;
char contorCerereID;
char receptie[5],receptieTemp[5];
char transmisie[8];
char date[20];
char pointerReceptie,pointerTransmisie;
char vartemp1,vartemp2,vartemp3;
char timeBaseL,timeBaseH;
char adresaTransmisie, dataTransmisie;
char genPWMPr2, genPWMPresc,genPWMLsb,genPWMdutyCycle;

short tmr1a,tmr1b,tmr1c;//variabile 16 biti pentru tmr1
short timeBase;//baza de timp
short tmr2b;//se va stoca valoarea lui tmr2 la sfarsit(timeBase=0)si se va lua in calcul la det. frecv.


void main(void)
{
//resetare RAM bank1:
for(fsr=32;fsr<110;fsr++)
	indf=0;
//resetare RAM bank2:
for(fsr=160;fsr<238;fsr++)
	indf=0;
//initializari:
eroareReceptie=0;
pointerReceptie=0;
pointerTransmisie=0;
ctrlTransmisie=0;
receptie[0]=0;
transmisie[0]=10;
ctrlReceptie=1;
tmr1a=0;
tmr1b=0;
startStopFrecv=0;
contorCerereID=0;

	
status=0;
clear_bit(intcon,GIE);
	
//initializare porturi
trisa=255;
trisb=11010011b;
option_reg=0;
intcon=01000011b;
pie1=00100011b;
pcon=0;
vrcon=0;
porta=0;
portb=0;
cmcon=7;	
pr2=249;

//INITIALIZARE TIMERE TMR1 & TMR2:
t1con=00000110b;
t2con=00000001b;
ccp1con=0;
pir1=0;

//initializare USART :
spbrg=64; //19200bps
txsta=00100100b;
rcsta=10010000b;

asm 
{
MOVF _rcreg,0;
MOVF _rcreg,0;
MOVF _rcreg,0;
}

clear_bit(rcsta,CREN);
set_bit(rcsta,CREN);
set_bit(intcon,GIE)	;

timeBaseL=136;
timeBaseH=19;//timebase=1s

loop:
nop();					
if(ctrlReceptie==0){	//s-a receptionat o comanda
	//cod ptr testare seriala
	ctrlReceptie=1;
	if(receptie[1]!=0)
		switch(receptie[2]){
					
			case 1:
			startStopFrecv=receptie[3];//start-stop frecventmetrul
			if(startStopFrecv==0){
				clear_bit(t1con,TMR1ON); //stop timer1
				clear_bit(t2con,TMR2ON);//stop frecv
				clear_bit(pie1,TMR2IE);
				clear_bit(pir1,TMR2IF);
			}
			
			else{ 
				startStopGenSemnal=0;//stop gen semnal daca era activat
				ccp1con=0; //stop ccp daca este activat;
				tmr1a=0;
				tmr1l=0;
				tmr1h=0;
				tmr2=0;
				MAKESHORT(timeBase,timeBaseL,timeBaseH);
				contorCerereID=0;
				pr2=249;
				t2con=00000001b;
				set_bit(t2con,TMR2ON);//start baza de timp
				set_bit(t1con,TMR1ON);
				set_bit(pie1,TMR2IE);
				clear_bit(pir1,TMR2IF);
			}
			break;
			
			case 2:
			timeBaseL=receptie[3];
			break;
			
			case 3:
			timeBaseH=receptie[3];
			MAKESHORT(timeBase,timeBaseL,timeBaseH);
			contorCerereID=0;
			break;
			
			case 4:
			//startStop generator PWM semnal
			startStopGenSemnal=receptie[3];
			startStopFrecv=0;
			clear_bit(pie1,TMR2IE);//disable intreruperi tmr2
			clear_bit(t1con,TMR1ON); //stop timer1
			if(startStopGenSemnal==0){
				//cod pentru oprirea genSemnal
				clear_bit(t2con,TMR2ON);
				ccp1con=0;//disable ccp module
				clear_bit(portb,3);//ca sa nu ramana ledul aprins
			}
			else{
				clear_bit(t2con,TMR2ON);
				//cod pentru pornirea genSemnal
				pr2=genPWMPr2;
				//tmr2 prescaler:
				t2con=genPWMPresc;
				//duty_cycle:
				ccp1con=genPWMLsb;
				ccpr1l=genPWMdutyCycle;
				
				set_bit(t2con,TMR2ON);
				}
			break;
			
			case 5:
			//startStop generatorul PWM-se dezactiveaza frecventmetrul
			nop();
			break;
			
			case 6:
			//valoare frecventa(perioada) gen semnal;
			genPWMPr2=receptie[3];
			pr2=genPWMPr2;
			break;
			
			case 7:
			genPWMLsb=receptie[3];
			ccp1con=genPWMLsb;
			break;
			
			case 8:
			genPWMPresc=receptie[3];
			t2con=genPWMPresc;
			break;
			
			case 9:
			genPWMdutyCycle=receptie[3];
			ccpr1l=genPWMdutyCycle;
			break;
			
			default:
			break;
		}

	else{
		//cod pentru transmisie de stari!
		switch(receptie[2]){
			
			case 0:
			adresaTransmisie=receptie[3];
			dataTransmisie=183;	//cod de identificare modul
			contorCerereID=0;
			break;
			
			case 1:
			adresaTransmisie=receptie[3];
			dataTransmisie=startStopFrecv;//starea frecventmetrului
			break;
			
			case 3:
			adresaTransmisie=receptie[3];
			HIBYTE(dataTransmisie,timeBase);
			break;
			
			default:
			break;
		}
	set_bit(transmisieQueue,1);
	}
}

//rutina transmisie seriala:
if(ctrlTransmisie==0){		//portul de transmisie este liber
if(transmisieQueue==0)nop();
else if((transmisieQueue & 1) && (startStopFrecv!=0)){//transmisie frecventa:
	clear_bit(transmisieQueue,0);
	transmisie[1]=1;//vin date de la frecventmetru-fara o cerere prealabila!!!
	HIBYTE(vartemp1,tmr1b); //tmr1aH
	transmisie[2]=vartemp1;	
	LOBYTE(vartemp1,tmr1b);//tmr1aL
	transmisie[3]=vartemp1;
	HIBYTE(vartemp1,tmr1c);//tmr1H
	transmisie[4]=vartemp1;
	LOBYTE(vartemp1,tmr1c);//tmr1L
	transmisie[5]=vartemp1;
	transmisie[6]=tmr2b;
	set_bit(pie1,TXIE);
	}
else if(transmisieQueue & 2){
	clear_bit(transmisieQueue,1);
	transmisie[1]=0;
	transmisie[2]=adresaTransmisie;
	transmisie[3]=dataTransmisie;
	transmisie[4]=0;
	transmisie[5]=0;
	transmisie[6]=0;
	set_bit(pie1,TXIE);
	}
}
	

goto loop;

}//end main

void interrupt(void){
if(pir1	&	00000010b) timeBaseTmr2();	
if(pir1 & 00000001b) tmr1();				//TMR1IF=1 intrerupere timer TMR1
if(pir1 & 00100000b) receptieSeriala();
if((pir1 & 00010000b) && (pie1 & 00010000b)) transmisieSeriala();
return;
}

void receptieSeriala(void){
char recTemp;
asm{
	BCF		_status,RP0
	BTFSC	_rcsta,OERR
	GOTO	OVERERROR
	BTFSC	_rcsta,FERR
	GOTO	FRAMEERROR
	GOTO	ENDASM
OVERERROR:
	BCF		_rcsta,CREN
	MOVF	_rcreg,0
	MOVF	_rcreg,0
	MOVF	_rcreg,0
	BSF		_rcsta,CREN
	return
FRAMEERROR:
	MOVF	_rcreg,0
	return
ENDASM:
}
inceputRec:
recTemp=rcreg;
if(pointerReceptie==0 && recTemp==10){
	pointerReceptie=1;
	receptieTemp[0]=recTemp;
	ctrlReceptie=1;
	}
else if(pointerReceptie!=0){
	receptieTemp[pointerReceptie]=recTemp;
	pointerReceptie++;
	}
if(pointerReceptie==4){
pointerReceptie=0;
ctrlReceptie=0;
receptie[0]=receptieTemp[0];
receptie[1]=receptieTemp[1];
receptie[2]=receptieTemp[2];
receptie[3]=receptieTemp[3];
receptie[4]=receptieTemp[4];
}

if(pir1 & 00100000b) 
	goto inceputRec;

return;
}

void transmisieSeriala(void){
inceputTr:
ctrlTransmisie=1;
txreg=transmisie[pointerTransmisie];
pointerTransmisie++;
if(pointerTransmisie==7){
	pointerTransmisie=0;
	if(startStopGenSemnal==0) clear_bit(portb,3);
	ctrlTransmisie=0;
	clear_bit(pie1,TXIE);
	}
else if(pir1 & 00010000b) goto inceputTr;
return;
}

void tmr1(void){
tmr1a++;
clear_bit(pir1,TMR1IF);
}

void timeBaseTmr2(void){
if(startStopFrecv!=0){
if(timeBase==0){
	clear_bit(t1con,TMR1ON);	//stop timer1
	clear_bit(t2con,TMR2ON);	//stop baza de timp
	tmr1b=tmr1a;
	
	MAKESHORT( tmr1c, tmr1l, tmr1h );
	
	tmr1a=0;
	tmr1l=0;
	tmr1h=0;
	
	tmr2b=tmr2;//se va utiliza la det. frecv.
	tmr2=0;
	MAKESHORT(timeBase,timeBaseL,timeBaseH);
		
	set_bit(t2con,TMR2ON);//se porneste baza de timp
	set_bit(t1con,TMR1ON);//se porneste timer1
	//transmisie tmr1b, tmr1c;
	if(startStopGenSemnal==0) set_bit(portb,3);
	set_bit(transmisieQueue,0);//punere in coada transmisia frecventei
	switch(timeBaseL){
		case 244: //baza de timp =0.1s
		contorCerereID++;
		break;
		
		case 136: //baza de timp=1s
		contorCerereID+=10;
		break;
		
		case 80: //baza de timp=10s
		contorCerereID+=30;
		break;
	}
	if(contorCerereID>=50){clear_bit(portb,3); startStopFrecv=0; clear_bit(t2con,TMR2ON);}//opresc frecv pentru ca modulul este deconectat de la PC
	}
	
timeBase--;
}
clear_bit(pir1,TMR2IF);
}

