/*********************************************************
* mnscene.c												 *
* Multipaires analogique a transmission numerique.		 *
* Code du NIOS2 du module "scene"						 *
* JMc Villers (33)							 	  		 *
**********************************************************/

#include "alt_types.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include "system.h"
#include "sys/alt_alarm.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "mesdefs.h"

#define DBG (0)
#define	INIT_PGA	0x9000

void	data_vers_les_pga(void);

/* Affectation des lignes de port sur MN_PIO_BIDIR
SPI des PGA2505
CS				0
CLK				1
SDO (vers SDI)	2

SPI du PIC federateur de CLIPs
CLK				8
CS				10
DATA			11
OVR				5  Clippe des PGA via le PIC federateur
*/
/*
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
Trames de controle et de commandes echangees avec le module console:
Elles sont echangees via les deux ports paralleles 32 bits du NIOS.
Chaque port presente 32 bits en entree (VHDL vers NIOS2) et 32 bits en sortie (NIOS2 vers VHDL).

Dans le sens console -> scene, elles transportent les donnees de configuration
de chaque PGA.
Dans le sens scene -> console, elles tranportent les CLIPs de chaque PGA.
Les constantes sont des motifs binaires qui permettent des tests de positionnement dans la trame.
NM_PIO1 :
32 bits en sorties:0x65-XX-YY-ZZ - Attention! b7 et b6 de 0x65 ne sont pas transmis sur le LVDS. Voir design VHDL.
32 bits en entrees:0x65-0x00-0x00-0x00 - Chaque octet est recu du module console.

NM_PIO2 :
32 bits en sorties:0x00-0x00-0x00-0xA6
32 bits en entrees:AA-BB-CC-0xA6 - Chaque octet est recu du module console.

Cas des donnees en sortie depuis le NIOS2:
XX->Clip voies 24 a 17
YY->Clip voies 16 a 9
ZZ->Clip voies 8 a 1

Cas des donnees en entree vers le NIOS2:
AA->	Si 40 et 41:BB et CC sont pour le PGA 1
		Si 42 et 43:BB et CC sont pour le PGA 2
		Si 44 et 45:BB et CC sont pour le PGA 3
		Si 46 et 47...
AA ne commence pas a 0 pour eviter d'interpreter une succession erronee de bits
a 0 recue du LVDS comme AA=0. En effet, il est possible en cas de probleme
sur la liaison qu'une telle suite se presente.
Pour chaque PGA, on envoie donc deux fois consecutivement la meme trame (avec AA=x
pour la premiere et AA=x+1 pour la suivante) afin de pouvoir controler l'integrite.
BB->b15 a b8 pour la configuration du PGA designe par AA (bit /DC a D1)
CC->b7 a b0 pour la configuration du PGA designe par AA (bit 0 a G0)
*/

/* Exploite aussi par les routines I2C */
//mot copie_bidir_port;

octet tampon[128];

mon_champ_16 donnees4PGA[24], donnees4PGA_recues[24], donnees4PGA_recues_suivantes[24];

// Rang des bits sur le port bidirectionnel
#define RANG_CS_PGA		0x0001
#define RANG_CLK_PGA	0x0002
#define RANG_SDO_PGA	0x0004
#define RANG_OVR_PGA	0x0020 // Demande d'attention du PIC, il y a un (des) clip(s) a transmettre
#define RANG_OVR_CLK	0x0100 // Pilotage de la clk pour la voie serie synchrone avec le PIC des clips
#define RANG_OVR_CS		0x0400 // Pilotage du CS pour la voie serie synchrone avec le PIC des clips
#define	RANG_OVR_DATA	0x0800 // Reception des donnees depis le PIC des clips par la voie serie synchrone


// Envoi de la configuration des 24 PGA2505.
// Rappel : Les PGA sont chaines sur la ligne de donnees.
void	data_vers_les_pga(void)
	{octet o;
	 mot m;
	 char c;

	 	IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_CS_PGA);
	 	 for(c = 23; c>=0; c--)
			{m =  donnees4PGA[c].tout_a_la_fois;

			if DBG printf("data_vers_les_pga():voie[%d]=%X\n", c, m);
			 for(o = 0; o<16; o++)
					{if (m & 0x8000)	IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_SDO_PGA);
				 	 	 	 	 else	IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_SDO_PGA);
				 	 m<<=1;
				 	 IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_CLK_PGA);
				 	 IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_CLK_PGA);
					}
			}
		 IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_CS_PGA);
	}


//Fonction installee a la creation du projet sous Eclipse.
// Les messages s'affichent sur une console NIOS2 sous Eclipse vai le JTAG.	
static void initial_message()
{
    printf("\n\n**************************\n");
    printf("* Hello from Nios II!    *\n");
    printf("* Multipaires numerique  *\n");
    printf("* Module de scene        *\n");
    printf("* JMcV 2015 - 2016       *\n");
    printf("**************************\n");
}


int main(void)
{
    int  __attribute__ ((unused))  wait_time;  // Attribute suppresses "var set but not used" warning. Je ne sais plus...
    octet o, o1, trame_pic_ovr[5];
    longmot lm1, lm2;
    octet cpt_data_pga_deja_recues;	// Pour le mecanisme du mute a la MST: On coupe le mute une fois que les 24 PGAs ont ete configures
									// depuis le module console.
    								// Le but ultime a atteindre est de laisser le temps aux relais des PADs pour basculer.

	// Initialisation des direction de MN_PIO_BIDIR_BASE. 0 -> entree / 1 -> sortie
    IOWR_ALTERA_AVALON_PIO_DIRECTION(MN_PIO_BIDIR_BASE, 0x15C7);
	// Initialisation des lignes en sortie.
    IOWR_ALTERA_AVALON_PIO_DATA(MN_PIO_BIDIR_BASE, 0x00C1);

    if DBG initial_message();// NIOS2 vivant ? Bonne version du programme ?
    usleep(1000000);

    // Initialisation des PGA
    cpt_data_pga_deja_recues = 0;
    for(o=0; o<24; o++) donnees4PGA[o].tout_a_la_fois = INIT_PGA;
    for(o=0; o<24; o++) donnees4PGA_recues[o].tout_a_la_fois = INIT_PGA;
    for(o=0; o<24; o++) donnees4PGA_recues_suivantes[o].tout_a_la_fois = INIT_PGA;
    data_vers_les_pga();
	// Par la suite, les donnees seront envoyees aux PGA uniquement lorsqu'un changement de configuration est demande.
	// De plus, les donnees de configuration etant transmises a l'identique sur deux trames consecutives,
	// il faut que les donnees de donnees4PGA_recues[] soient identiques aux donnees de donnees4PGA_recues_suivantes[] pour etre
	// copiees dans donnees4PGA[], tableau utilise pour l'envoi physique aux PGA.
	
	// On prepare la trame qui contiendra les eventuels CLIPs des voies.
    IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE, 0x65000000);
    IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO2_BASE, 0x000000A6);        

    while( 1 ) 
    {
		// Recuperation des donnees de configuration d'un PGA.
    	lm1 = IORD_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE);
    	lm2 = IORD_ALTERA_AVALON_PIO_DATA(NM_PIO2_BASE);

    	if (((lm1 & 0xFF000000) == 0x65000000) && ((lm2 & 0x000000FF) == 0xA6)) // Test de la presence des motifs de positionnement.
    		{
    		 o = (lm2>>24) & 0xFF; // o doit contenir AA entre 40 et 63 (voir protocole)
    		 o-=40;

    		 if ((o>=0) && (o<=47)) // Verification du numero de PGA.
    		 	 {
				 if (!(o & 0x01)) // Trame paire ?
								  { o1 = o; // Sauvegarde du numero de PGA pour verification sur la trame suivante.
				 	 	 	 	    o>>=1;
									o&=0x7F; // On ce stade, on a un numero de PGA entre 0 et 23.
									lm2>>=8; // Afin que b15 a b0 de lm2 contienne les 2 octets de config. du PGA
											 // Pour l'affectation ci-dessous.
									donnees4PGA_recues[o].tout_a_la_fois = lm2;
									// On casse la coherence pour eviter le cas ou donnees4PGA_recues[o] serait
									// egale a une ancienne donnees4PGA_recues_suivantes[o].
									donnees4PGA_recues_suivantes[o].tout_a_la_fois = donnees4PGA_recues[o].tout_a_la_fois + 1;
									}
									 else	 { if (o == (o1 + 1)) // On verifie que cette trame est bien celle qui correspond a la precedente.
										 	 	 { o>>=1;
												   o&=0x7F; // On ce stade, on a un numero de PGA entre 0 et 23.
												   lm2>>=8; // Afin que b15 a b0 de lm2 contienne les 2 octets de config. du PGA
															// Pour l'affectation ci-dessous.
												   donnees4PGA_recues_suivantes[o].tout_a_la_fois = lm2;
												   if (donnees4PGA_recues[o].tout_a_la_fois == donnees4PGA_recues_suivantes[o].tout_a_la_fois)
												   						 {if (donnees4PGA_recues[o].tout_a_la_fois != donnees4PGA[o].tout_a_la_fois)
												   								 {donnees4PGA[o].tout_a_la_fois = donnees4PGA_recues[o].tout_a_la_fois;
												   								  if DBG printf("Rang:%d - data= %X\n", o, donnees4PGA_recues[o].tout_a_la_fois);
												   								  data_vers_les_pga();
																				  
																				  // On veille a ne pas commander tous les relais en meme temps a la MST. Est-ce bien utile ?...
												   								  if (cpt_data_pga_deja_recues < 24) 	  // Afin d'attendre la reception d' un cycle complet de configuration des PGAs,
												   									  	  	  	  	  	  	  	  	  	  // quelque soit l'instant de la MST.
												   									  	  	  	  	  {if 	((donnees4PGA[o].tout_a_la_fois & 0x0F00) != 0) // Y'a t-il un relais a basculer ?
												   									  	  	  	  		  	  	  	  	  	  	  usleep(300000); // Laisser du temps a la commutation mecanique.
												   									  	  	  	  	    cpt_data_pga_deja_recues++;
												   									  	  	  	  	  }
																									  
												   								  if (cpt_data_pga_deja_recues == 24)
												   								  	  {usleep(1000000); // Le temps que tout se stabilise vraiment. Est-ce bien utile ?...
												   									   IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, 0x1000); // On supprime le mute des voies.
												   								  	   cpt_data_pga_deja_recues = 25; // On indique que la phase de MST est passee.
												   								  	  }
												   								 }
												   						 }
										 	 	 }
											 }
    		 	 }
    		}

		// On s'occupe maintenant de l'envoi des CLIPs. Lors d'un(des) CLIP(s), le PIC multiplexeur signale qu'il
		// faut venir lui recuperer une trame de 5 octets par une liaison SPI (Le PIC est esclave) :
		// La trame en prevenance du PIC est composee ainsi : 0x55 - o1 - o2 - o3 - 0x6A
		// o1 : Clip de V1 a V8
		// o2 : Clip de V9 a V16
		// o3 : Clip de V17 a V24
    	if (!(IORD_ALTERA_AVALON_PIO_DATA(MN_PIO_BIDIR_BASE) & RANG_OVR_PGA)) // Le PIC signale t-il un(des) clip(s) ?
    	    						{// On recupere la trame de 5 octets.
									 IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_OVR_CS);
    	    						 for(o=0; o<5; o++)
    	    							{
										 for(o1=0; o1<8; o1++)
											{IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_OVR_CLK);
											 IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_OVR_CLK);
											 trame_pic_ovr[o]<<=1;
											 trame_pic_ovr[o]&=0xFE;
											 for(lm1=0; lm1<10; lm1++); // Attente de positionnement de la donnee par le PIC
											 	 	 	 	 	 	 	// Avec 50, front montant sur clk toutes les 57 us.
											 	 	 	 	 	 	 	// Avec 25, front montant sur clk toutes les 32 us.
											 	 	 	 	 	 	    // Avec 15, front montant sur clk toutes les 25 us.
											 	 	 	 	 	 	 	// Avec 10, front montant sur clk toutes les 20 us. Les 5 octets sont lus
											 	 	 	 	 	 	 	// en 816 us.
											 	 	 	 	 	 	    // Tests effectues avec un PIC a 40 MHz
																		// Le PIC au final est a 64 MHz.
											 trame_pic_ovr[o]+=(IORD_ALTERA_AVALON_PIO_DATA(MN_PIO_BIDIR_BASE) >> 11) & 0x00000001;
											}
    	    							}
    	    						 IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_OVR_CS);
									 
									 //
    	    						 //printf("trameZA_pic_ovr=%X-%X-%X-%X-%X\n", trame_pic_ovr[4], trame_pic_ovr[3], trame_pic_ovr[2], trame_pic_ovr[1], trame_pic_ovr[0]);
    	    						 if ((trame_pic_ovr[0] == 0x55) && (trame_pic_ovr[4] == 0x6A)) // Test de la presence des motifs de positionnement.
													 {lm1 = 0x6500;
													  lm1+=trame_pic_ovr[3];
													  lm1<<=8;
													  lm1+=trame_pic_ovr[2];
													  lm1<<=8;
													  lm1+=trame_pic_ovr[1];
													  //printf("trameZB_pic_ovr=%lX\n", lm1);
													  // Affectation du port NIOS2
													  IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE, lm1);
													 }
												 else IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE, 0x65000000);
											}
    	    			else		{IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE, 0x65000000); // Aucun CLIP a signaler.
    	    						}

    	} /* Fin de la boucle infinie */

    return 0;
}

