
/* 

   Copyright (C) Arnaud Houdelette		2012-2014
   Copyright (C) Emmanuel Langlois		2012-2014

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// definition des fonction cbi sbi idem assembleur
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif 

#include "USBAPI.h"
#include "USBDesc.h"


// déclaration des tableaux de données
byte tab_input_pc[1026];  // venant du pc
byte tab_input_dmx[534]; // données venant de l'extérieur : les 512 premiers DMX; les 20 suivant 4x8 bp + 16 analogique 8bits ; 1 octet d'etat
// reception
volatile int index_input_pc=0; // entrée serial 0
volatile int index_output_pc=0; // sortie serial 0
volatile int index_input_dmx=513; // entrée dmx
volatile int index_output_dmx=0; //sortie dmx -2 en attente de fin de transmission; -1 break; 0 à 512 transmission 
volatile int index_output_dmx2=0; //sortie dmx -2 en attente de fin de transmission; -1 break; 0 à 512 transmission 
volatile int etat_input_pc=0; // 0 raz ; 1 esc reçu ; 2 D reçu : pret à recevoir ; 3 prèt à emmetre
volatile int start_code_rec=-1;
char key; // caractère reçu serial 0
int cpt_ana = 0;
int ledPin = 13; // led interne
int tx1pin = 18; // pin DMX serial 1
int tx2pin = 16; // pin DMX serial 2

byte brk_timer_start=181; // def : 150us
byte mab_timer_start=231; //def : 50us
int  nb_circuits=512;
int flag_merge1=1;
int flag_merge2=1;


void acceptchar(char c)
{
  
  USB_Flush(CDC_TX);
}

// vecteur d'inéruption pour reception pc
/*
ISR(USART0_RX_vect)
{
	char c,r;
	byte *pb, *pe;
	r = UCSR0A;
	c = UDR0;
	switch (etat_input_pc) {
	
	case 0:
		// on attend un 'esc' pour commencer
		if (c==27) { etat_input_pc=1; digitalWrite(ledPin, LOW);break;}

		break;
		
	case 1:
		// on attend 'D' pour recevoir
		if (c==68) {
			etat_input_pc=2;
			index_input_pc=1;
			tab_input_dmx[533]=68;
			index_output_pc=1; // on init l'index d'emmission vers le pc ( le 0 n'est pas emit => start code)
			sbi(UCSR0B, UDRIE0); // activation de l'intéruption registre emmission 
		}
		// Esc 'C' réinit
		if (c==67) {
			etat_input_pc=0;

			pe=tab_input_pc+1026;
			for(pb=tab_input_pc;pb<pe;pb++) *pb=0;

			pe=tab_input_dmx+533;
			for(pb=tab_input_dmx;pb<pe;pb++) *pb=0;

			tab_input_dmx[533]=67;
			index_output_pc=533; // on init l'index d'emmission vers le pc ( uniquement etat : 67 'C' )
			sbi(UCSR0B, UDRIE0);
			break;

		}
		// Esc 'B' parametrage
		if (c==66) {etat_input_pc=10; }

		// Esc 'A' probe 
		if (c==65) {etat_input_pc=0;
			tab_input_dmx[533]=65;
			index_output_pc=533; // on init l'index d'emmission vers le pc ( uniquement etat : 65 'A' )
			sbi(UCSR0B, UDRIE0);
		}
		
		// si aucune commande n'est trouvée (toujours à 1) on repart à 0
		if (etat_input_pc==1) {etat_input_pc=0;}
		break;
		
	case 2: // reception trame pc
		// on rempli le tableau
		tab_input_pc[index_input_pc]=c;
		index_input_pc++;
		// si on arrive à 1024
		if (index_input_pc > 1024) {// on se prépare à emmetre vers le pc       
		etat_input_pc=0;
		digitalWrite(ledPin, HIGH);         

		}
		break;
		
	case 10: // 1er parametre : nb de circuits / 2 - 1 ( de 2 a 512 )
		etat_input_pc++; 
                //nb_circuits= ((int)c)*2 + 2;
		break;
		
	case 11: // 2nd parametre : duree du break en us
		etat_input_pc++; 
		//brk_timer_start = 255 - (c/2) +1;
		break;
		
	case 12: // 3eme parametre : duree du mab en us
		etat_input_pc++;
		//mab_timer_start = 255 - (c/2) +1;
		break;
		
	case 13: // 4eme parametre : merge
		etat_input_pc=0;
		flag_merge1 = c & 1;
                flag_merge2 = c/2 & 1;
		// on a tout recu, on reponds
		tab_input_dmx[533]=66;
		index_output_pc=533; // on init l'index d'emmission vers le pc ( uniquement etat : 66 'B' )
		sbi(UCSR0B, UDRIE0);

		break;
	default:
		// on fait rien
		break; 
	}

}*/


// vecteur d'intéruption pour reception dmx
ISR(USART1_RX_vect)
{
  char c,r;
  r = UCSR1A;
  c = UDR1;
  if (r & (1<<FE1))  {index_input_dmx=0;return;}    
  if ( index_input_dmx==0 && c!=0 ) {index_input_dmx=513; }
  if ( index_input_dmx<=512 ) 
  {
      tab_input_dmx[index_input_dmx]=c;
      index_input_dmx++;
  }
}  



// vecteur d'intéruption pour transmission DMX sur serial 1
// vecteur : USART 1 transmission buffer vide
ISR(USART1_TX_vect)
{
  // si l'USART 1 est vide => break
  if(index_output_dmx==-4)
    index_output_dmx=-1;
}
// vecteur : USART 1 transmission registre vide
ISR(USART1_UDRE_vect)
{
  if (index_output_dmx>=0) { //si index >=0 caratère suivant
    if (flag_merge1==1) {UDR1 = max(tab_input_pc[index_output_dmx],tab_input_dmx[index_output_dmx]);}
      else {UDR1 = tab_input_pc[index_output_dmx];}
    index_output_dmx++;
  } 
  // si 512 transmits => mise en attente de fin de transmission
  // desactivation de l'intéruption sur le registre
  if (index_output_dmx>nb_circuits) {index_output_dmx=-4;cbi(UCSR1B, UDRIE1);}
  
}
/*
// vecteur d'intéruption pour transmission DMX sur serial 2
// vecteur : USART 1 transmission buffer vide
ISR(USART2_TX_vect)
{
  // si l'USART 2 est vide => break
  if(index_output_dmx2==-4)
    index_output_dmx2=-1;
}
// vecteur : USART 2 transmission registre vide
ISR(USART2_UDRE_vect)
{
  if (index_output_dmx2>=0) { //si index >=0 caratère suivant
    if (flag_merge2==1) {UDR2 = max(tab_input_pc[index_output_dmx2+512],tab_input_dmx[index_output_dmx2]);}
      else {UDR2 = tab_input_pc[index_output_dmx2+512];}
    index_output_dmx2++;
  } 
  // si 512 transmits => mise en attente de fin de transmission
  // desactivation de l'intéruption sur le registre
  if (index_output_dmx2>nb_circuits) {index_output_dmx2=-4;cbi(UCSR2B, UDRIE2);}
  
}
// vecteur d'intéruption pour transmission vers le pc sur serial 0
// vecteur registre de transmission
ISR(USART0_UDRE_vect)
{
  //caratère suivant
  UDR0 = tab_input_dmx[index_output_pc];
  index_output_pc++;
  if (index_output_pc>532) {
    cbi(UCSR0B, UDRIE0);
  }
}*/

ISR(TIMER2_OVF_vect) {
  if (index_output_dmx==-2 ) {
    digitalWrite(tx1pin, HIGH); // on met la broche 18 à 1 pendant 10 µs
    digitalWrite(tx2pin, HIGH); // on met la broche 16 à 1 pendant 10 µs
    //digitalWrite(ledPin, HIGH); 
    index_output_dmx=-3;
    index_output_dmx2=-3;
    TCNT2 = mab_timer_start ;// RAZ compteur timer
    TIFR2 = 0 ; //Clear Flags timer 
    return; 
  }
  if (index_output_dmx==-3 ) {
    sbi(UCSR1B, TXEN1);  // on redémarre la transmission
    index_output_dmx=0; // on se prépare à émmettre à partir du stat code ( 513 octets )
    sbi(UCSR1B, UDRIE1); // on réactive l'intéruption du registre
    
  /*  sbi(UCSR2B, TXEN2);  // on redémarre la transmission
    index_output_dmx2=0; // on se prépare à émmettre à partir du stat code ( 513 octets )
    sbi(UCSR2B, UDRIE2); // on réactive l'intéruption du registre    */
    
    TIMSK2 = 0 ; //desactivation intéruption A &B
    TCCR2B = 0;
  }
}


void setup() {
 // initialisation du stat code à 0
 tab_input_pc[0]=0; 
  
  
  
 // initialisation de la liaison série pc à 0,5MB/s
/*   UCSR0A = 1 << U2X0;
   UBRR0H=0;
   UBRR0L = 3;
   UCSR0C = 6;*/
 
 
 // initialisation à 250k de serial 1
   // baudrate
   UCSR1A = 1 << U2X1;
   UBRR1H=0;
   UBRR1L = 7;
 
   // 2 bit de stop; pas de parité; 8 bits de données
   UCSR1C = 14;
 
  /*
 // initialisation à 250k de serial 2
   // baudrate
   UCSR2A = 1 << U2X2;
   UBRR2H=0;
   UBRR2L = 7;
 
   // 2 bit de stop; pas de parité; 8 bits de données
   UCSR2C = 14;*/
 
   // activation transmission et intéruption serial 1
  sbi(UCSR1B, RXEN1);  //Reception
  sbi(UCSR1B, TXEN1);  //Transmission
  sbi(UCSR1B, RXCIE1); //Interruption sur reception
  sbi(UCSR1B, TXCIE1); //Interruption pour fin de transmission

   // activation transmission et intéruption serial 2
/*  sbi(UCSR2B, TXEN2);  //Transmission
  sbi(UCSR2B, TXCIE2); //Interruption pour fin de transmission
  
  sbi(UCSR0B, RXEN0);  //Reception
  sbi(UCSR0B, RXCIE0); //Interruption sur reception
  sbi(UCSR0B, TXEN0);  //Transmission*/


/* // Init convertion analogique pour le premier canal pin0
 ADCSRB = (ADCSRB & ~(1 << MUX5));
 ADMUX = 96; //01100000 reférence sur le 5v et alignement pour lecture sur 8 bits
 sbi(ADCSRA, ADSC);*/
 
 // init timer break 
 TIMSK2 = 0;
 TCCR2B = 0;
 TCCR2A = 0; //  00000000
// ASSR &= ~(1<<AS2);                                                                          <---------------------------
 TCNT2 = 0; // compteur 
 OCR2A = 220 ; // 100µs
 OCR2B = 200 ; // 110µs
  
 sei();
 // init pin led interne en sortie
 pinMode(ledPin, OUTPUT); 
 digitalWrite(ledPin, LOW);
 
 
 // préparation du premier break
 index_output_dmx=-1;
 index_output_dmx2=-1;
// PORTA = 255;
// DDRA = 0;
// PORTC = 255;
// DDRC = 0;
 tab_input_dmx[533]=0;
}

void loop() {

// génération du break en tache principale
 int cpt = 0; 
 if (index_output_dmx==-1 && index_output_dmx2==-1 ) {
  index_output_dmx=-2;
  index_output_dmx2=-2;
  pinMode(tx1pin, OUTPUT); // on met la broche 18 en mode sortie
  pinMode(tx2pin, OUTPUT); // on met la broche 16 en mode sortie
  cbi(UCSR1B, TXEN1);  //on stop la transmission 
//  cbi(UCSR2B, TXEN2);  //on stop la transmission
  digitalWrite(tx1pin, LOW); // on met la broche 18 à 0
  digitalWrite(tx2pin, LOW); // on met la broche 16 à 0
  TCNT2 = brk_timer_start ;// RAZ compteur timer
  TIFR2 = 0 ; //Clear Flags timer 
  TIMSK2 = 1 ; //activation intéruption A &B 
  TCCR2B = 3; // 00000011 division par 32 de l'horloge base => 2µs
 }    // fin du break
 
 // suite du code
// tab_input_dmx[513]= PINA;
 //tab_input_dmx[514]= PINC;
 tab_input_dmx[515]=0;
 tab_input_dmx[516]=0; 
/* if ( ! bit_is_set(ADCSRA, ADSC)) {
   //digitalWrite(ledPin, HIGH);
  tab_input_dmx[517+cpt_ana++]=ADCH;
  if (cpt_ana>15) cpt_ana=0;
  ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((cpt_ana >> 3) & 0x01) << MUX5);
  ADMUX = 96 | (cpt_ana & 0x07);
  sbi(ADCSRA, ADSC);
 }*/
}


