/*************************************************************************
 * mnconsole.c															 *
 * Multipaires analogique a transmission numerique.						 *
 * Code du NIOS2 du module "console"									 *
 * JMc Villers (33)							 				 			 *
 *																		 *
 * Les fonctions de bas niveau et propres au WIZNET sont dans WIZutil.c  *
 *************************************************************************/

#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 <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "mesdefs.h"
#include "sys/alt_flash.h"
#include "WIZ.h"

#define DBG (0)
#define	INIT_PGA		0xB001 // Valeur de configuration par defaut des PGA2505
#define RANG_CS_FRAM	0x80 // La F-RAM est une FM25L04B, soit 512 octets

/* Affectation des lignes de port:
 Sur MN_PIO_BIDIR, port NIOS2 bidirectionnel de 16 bits
 On a le WIZNET et la F-RAM en SPI emule logiciellement.
RESET			0
INT				1
SCS				2
SCLK			3
MOSI			4
MISO			5
RANG_CS_FRAM	7
On a 2 leds de la platine Cyclone
LED CLIP	8 : Indique qu'au moins une voie clippe.
LED LVDS	9 : Indique un probléme de reception LVDS, quelque soit le sens.
BPReset		10
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
Trames de controle et de commandes echangees avec le module de scene:
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-0x00-0x00-0x00
32 bits en entrees :WW-XX-YY-ZZ

NM_PIO2 :
32 bits en sorties :AA-BB-CC-0xA6
32 bits en entrees :VV-UU-TT-0xA6

Cas des donnees en entree vers le NIOS2:
WW->b7 etat de la synchro LVDS console->scene. b6 etat de la synchro LVDS scene->console.
b5 a b0 : 0x25 recu du module de scene.
XX->Clip voies 24 a 17
YY->Clip voies 16 a 9
ZZ->Clip voies 8 a 1
VV->Presence signal des voies 24 a 17
UU->Presence signal des voies 16 a 9
TT->Presence signal des voies 8 a 1
0xA6 est recu du module de scene.

Cas des donnees en sortie depuis 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 au niveau
du module de scene avant ecriture dans les PGA2505.
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)
*/

mot copie_bidir_port;

octet tampon[128];
mon_champ_16 donnees4PGA[24];
const char intitules_voies_origine[24][10]={"V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8", "V9", "V10", "V11", "V12",
		"V13", "V14", "V15", "V16", "V17", "V18", "V19", "V20", "V21", "V22", "V23", "V24"};
char intitules_voies[24][10];

octet trame_etat[64] = {0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6};
octet flg_envoi_etat, etat_lvds_scene2console_precedent, etat_lvds_console2scene_precedent;

octet tampon_fram[64];
void ecrt_fram(mot nombre, octet *depuis, octet cmde, octet adresse);
void lect_fram(mot nombre, octet *vers, octet cmde, octet adresse);
void write_config_des_PGA_en_fram(void);
octet lect_config_des_PGA_en_fram(void);
void write_config_un_PGA_en_fram(octet voie);
void write_intitule_une_voie_en_fram(octet voie);
void lect_intitule_une_voie_en_fram(octet voie);

extern octet delai_wd_cnx_sock1;
extern mon_champ_8 etat_sock1;

mon_champ_8 flag_divers; /* b0:1->Envoyer une trame Signal/Clip sur la socket 2 (UDP)
							b1:1->Identifiants (IP et port) de la socket 1 de commande a recuperer
								  suite a une demande de chargement de l'etat du multipaires pouvant
								  etre consecutif a un changement de terminal, il faut communiquer les identifiants
								  reseau (MAC, IP) a la socket 2 a partir des donnees de la socket 1.
								  Rappel : Pour la socket 2 en UDP : MNcontrol est serveur.
							b2:1->Renseignement de la socket 2 effectue depuis la MST (voir b1 ci-dessus). Cela evite
								  d'envoyer des donnees avec la socket 2 vers n'importe ou.
 	 	 	 	 	 	 */
mot port_tcpudp;
octet ip1, ip2, ip3, ip4;
octet masq1, masq2, masq3, masq4;
octet gw1, gw2, gw3, gw4;

// Fonction appelee toutes les 100 ms. Utilisee pour verifier si un(des) CLIP(s), ou une(des) "presence(s) signal",
// un changement d'etat LVDS ont eu lieu.
// Utilisee aussi pour le watchdog de la connexion TCP de la socket1. Si une connexion est trop longue, on considere
// qu'il y a un probleme, que le client n'est plus la. Une reinitialisation de la socket suivra.
alt_u32 my_alarm_callback (void* context)
{longmot lm1, lm2, lm1_front, lm2_front, lm_tmp;
 octet o, flg_etat_led_clip;

  if (delai_wd_cnx_sock1) delai_wd_cnx_sock1--;

  // Lecture des ports NIOS2
  lm1 = IORD_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE);
  lm2 = IORD_ALTERA_AVALON_PIO_DATA(NM_PIO2_BASE);

  // Y'avait-il eu des fronts montants sur les ports pendant les 100 ms?
  // En effet, un bit peut-etre retombe a 0 et le changement d'etat non vu.
  lm1_front = IORD_ALTERA_AVALON_PIO_EDGE_CAP(NM_PIO1_BASE);
  IOWR_ALTERA_AVALON_PIO_EDGE_CAP(NM_PIO1_BASE, lm1_front); // Reinitialisation de la detection de front.
  lm2_front = IORD_ALTERA_AVALON_PIO_EDGE_CAP(NM_PIO2_BASE);
  IOWR_ALTERA_AVALON_PIO_EDGE_CAP(NM_PIO2_BASE, lm2_front);

  // Les etats des liaisons LVDS sont traitees par scrutation car on a besoin
  // de connaitre le retour de la liaison ET AUSSI la rupture. Or, seule la
  // detection de front montant est possible sur les ports.
  // Cas de la liaison scene -> console.
  if ((lm1 & 0x7F000000) == 0x65000000) // b7 et b6, etat des liaisons LVDS, b5 a b0 en relation avec le 0x25 envoye par la console.
	  	  {if (!etat_lvds_scene2console_precedent)
	  	   	   	   {trame_etat[0]|=0x40;
	  		   	    etat_lvds_scene2console_precedent = 1;
	  	   	   	    flg_envoi_etat = 1;
	  	   	   	   }
	  	  }
  	  	  else {if (etat_lvds_scene2console_precedent)
					   {trame_etat[0]&=0x3F; // On force aussi a 0 l'etat de console -> scene car imposssible de connaitre
						etat_lvds_scene2console_precedent = 0; 	// l'etat de la LVDS console -> scene si la liaison scene vers
						flg_envoi_etat = 1;						// console est plantee.
					   }
  	  	  	  }

  // On evalue l'etat de la liaison console -> scene uniquement si la liaison scene -> console est OK.
  if (((lm1 & 0xBF000000) == 0xA5000000) && ((trame_etat[0] & 0x40) == 0x40) )
 	  	  {if (!etat_lvds_console2scene_precedent)
 	  	   	   	   {trame_etat[0]|=0x80;
 	  	   	   	    etat_lvds_console2scene_precedent = 1;
 	  	   	   	    flg_envoi_etat = 1;
 	  	   	   	   }
 	  	  }
   	  	  else {if (etat_lvds_console2scene_precedent)
 					   {trame_etat[0]&=0x7F;
 					    etat_lvds_console2scene_precedent = 0;
 						flg_envoi_etat = 1;
 					   }
   	  	  	  }

   lm_tmp = lm1_front | lm1; 	// lm1_front permet de choper des clips ayant eu lieu entre deux passages dans my_alarm_callback()
   	   	   	   	   	   	   	   	// lm1 permet de choper des clips continus.

   flg_etat_led_clip = 0;

   // Cas des clips de V1 a V8
   o = lm_tmp;
   //if (((o ^ trame_etat[3]) & o) != 0) flg_etat_led_clip = 1;
   if ((o ^ trame_etat[3]) != 0) flg_envoi_etat = 1;
   trame_etat[3] = o;
   // Cas des clips de V9 a V16
   o = lm_tmp >> 8;
   if ((o ^ trame_etat[2]) != 0) flg_etat_led_clip = 1;
   trame_etat[2] = o;
   // Cas des clips de V17 a V24
   o = lm_tmp >> 16;
   if ((o ^ trame_etat[1]) != 0) flg_etat_led_clip = 1;
   trame_etat[1] = o;
   //if (flg_etat_led_clip) flg_envoi_etat = 1;

   // On allume la LED sur b8 de MN_PIO_BIDIR si un (des) clip(s) ont eu lieu.
   if (lm_tmp & 0xFFFFFF)
    	   IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, 0x100);
      else IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, 0x100);

   lm_tmp = lm2_front | lm2;

   // Cas des "presence signal" de V1 a V8
   o = lm_tmp >> 8;
   if ((o ^ trame_etat[6]) != 0) flg_envoi_etat = 1;
   trame_etat[6] = o;
   // Cas des "presence signal" de V9 a V16
   o = lm_tmp >> 8;
   if ((o ^ trame_etat[5]) != 0) flg_envoi_etat = 1;
   trame_etat[5] = o;
   // Cas des "presence signal" de V17 a V24
   o = lm_tmp >> 16;
   if ((o ^ trame_etat[4]) != 0) flg_envoi_etat = 1;
   trame_etat[4] = o;


   // On allume la LED sur b9 de MN_PIO_BIDIR si probleme LVDS
   if ( (!(trame_etat[0] & 0x40)) || (!(trame_etat[0] & 0x80)) )
   	   	   	IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, 0x200);
     else 	IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, 0x200);

return 100;  // Ainsi, my_alarm_callback est executee a nouveau dans 100 ms.
			 // Suffit de retourner 0 pour une execution unique.
}

// Ecriture de l'intitule d'une voie en F-RAM
// 0 <= voie <= 23
void write_intitule_une_voie_en_fram(octet voie)
	{octet cmde;
	 if (voie < 21) cmde = 0x02; else cmde = 0x0A;
	 ecrt_fram(10, (octet *) intitules_voies[voie], cmde, 50+voie*10);
	}
	
// Lecture de l'intitule d'une voie en F-RAM
// 0 <= voie <= 23	
void lect_intitule_une_voie_en_fram(octet voie)
	{octet cmde;
	 if (voie < 21) cmde = 0x03; else cmde = 0x0B;
	 lect_fram(10, (octet *) intitules_voies[voie], cmde, 50+voie*10);
	}

// Ecriture de la configuration de TOUS les PGA2505 en F-RAM	
void write_config_des_PGA_en_fram(void)
	{tampon_fram[0] = 0x65;
	 octet o, o2;

	 o2 = 1;
	 for(o=0; o<24; o++)
		 {tampon_fram[o2] = donnees4PGA[o].tout_a_la_fois>>8;
		  o2++;
		  tampon_fram[o2] = donnees4PGA[o].tout_a_la_fois;
		  o2++;
		 }
	 tampon_fram[49] = 0xA6;
	 ecrt_fram(50, tampon_fram, 0x02, 0);
	}

// Ecriture de la configuration d'un PGA2505 en F-RAM.
// 0 <= voie <= 23		
void write_config_un_PGA_en_fram(octet voie)
	{
	tampon_fram[0] = donnees4PGA[voie].tout_a_la_fois>>8;
	tampon_fram[1] = donnees4PGA[voie].tout_a_la_fois;
	ecrt_fram(2, tampon_fram, 0x02, 1+voie*2);
	}

// Lecture de la configuration des 24 PGA2505 en F-RAM.	
// Retourne 0 si la lecture est OK, sinon 1.
// Pour que la lecture soit OK, il faut que l'on ait le 0x65 en position 0
// et le 0xA6 en position 49.
octet lect_config_des_PGA_en_fram(void)
{octet o, o2;
 lect_fram(50, tampon_fram, 0x03, 0);
 if ((tampon_fram[0] == 0x65) && (tampon_fram[49] == 0xA6))
			{o2 = 1;
			 for(o=0; o<24; o++)
				 {donnees4PGA[o].tout_a_la_fois = tampon_fram[o2];
				  donnees4PGA[o].tout_a_la_fois<<=8;
				  donnees4PGA[o].tout_a_la_fois&=0xFF00;
				  o2++;
				  donnees4PGA[o].tout_a_la_fois+=tampon_fram[o2];
				  o2++;
				 }
			 return 0;
			}
 else return 1;
}


// Lecture de bas niveau de l'ecriture en F-RAM
// b3 de cmde est le A8 de l'adresse
void ecrt_fram(mot nombre, octet *depuis, octet cmde, octet adresse)
  { octet i=0;

    IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_CS_FRAM);
  	emis_recep_spi(0x06); // Commande WREN pour autoriser l'ecriture.
  	IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_CS_FRAM);

	IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_CS_FRAM);
	emis_recep_spi(cmde);
	if (nombre != 0) emis_recep_spi(adresse);
	for(;nombre!=0; nombre--)
		{
			emis_recep_spi(*(depuis+i));
			i++;
		}
	IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_CS_FRAM);
	}


// Ecriture de bas niveau de l'ecriture en F-RAM	
// b3 de cmde est le A8 de l'adresse
void lect_fram(mot nombre, octet *vers, octet cmde, octet adresse)
  { octet i=0;
	IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(MN_PIO_BIDIR_BASE, RANG_CS_FRAM);
	emis_recep_spi(cmde);
	emis_recep_spi(adresse);
	for(;nombre !=0; nombre--)
		{
			*(vers+i) = emis_recep_spi(0);
			i++;
		}
	IOWR_ALTERA_AVALON_PIO_SET_BITS(MN_PIO_BIDIR_BASE, RANG_CS_FRAM);
	}

//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 console        *\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...
    int i;
    octet o, o2, rang_pga;
    octet dip_1, dip_2, dip_3, dip_4;
    mot m;
    octet pilote_w5100[6];
    longmot lm1, lm2;

    static alt_alarm alarm; /* 1000 ticks par seconde, info pouvant etre obtenue avec alt_ticks_per_second() */

    flag_divers.tout_a_la_fois = 0x00;

	// Initialisation des direction de MN_PIO_BIDIR_BASE. 0 -> entree / 1 -> sortie
    IOWR_ALTERA_AVALON_PIO_DIRECTION(MN_PIO_BIDIR_BASE, 0x0000039D);
	// Initialisation des lignes en sortie.
    IOWR_ALTERA_AVALON_PIO_DATA(MN_PIO_BIDIR_BASE, 0x00000385);

	// Reinitialisation des detections de front.
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(NM_PIO1_BASE, 0xFFFFFFFF);
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(NM_PIO2_BASE, 0xFFFFFFFF);
	
	// Initialisation des parametres par defaut afin de fixer une configuration par defaut si
	// le bouton RESET du module FPGA est presse.
    for(rang_pga=0; rang_pga<24; rang_pga++) donnees4PGA[rang_pga].tout_a_la_fois = INIT_PGA;
    for(o=0; o<24; o++) strcpy(intitules_voies[o], intitules_voies_origine[o]);

	// Parametres réseau par defaut.
    ip1 = 192; ip2 = 168; ip3 = 1; ip4 = 122;
    masq1 = 255; masq2 = 255; masq3 = 255; masq4 = 0;
    gw1 = 192; gw2 = 168; gw3 = 1; gw4 = 1;
    port_tcpudp = 4050;

	
    etat_lvds_scene2console_precedent = 0;
    etat_lvds_console2scene_precedent = 0;
    flg_envoi_etat = 0;

    if DBG initial_message(); // NIOS2 vivant ? Bonne version du programme ?

	
    if (!(IORD_ALTERA_AVALON_PIO_DATA(MN_PIO_BIDIR_BASE) & 0x400)) // Si BP_reset presse, mise en configuration d'origine.
					{if DBG printf("BP RESET presse!\n");
					 write_config_des_PGA_en_fram();
					 for(o=0; o<24; o++) write_intitule_une_voie_en_fram(o);
					 tampon[0] = ip1; tampon[1] = ip2; tampon[2] = ip3; tampon[3] = ip4;
					 tampon[4] = masq1; tampon[5] = masq2; tampon[6] = masq3; tampon[7] = masq4;
					 tampon[8] = gw1; tampon[9] = gw2; tampon[10] = gw3; tampon[11] = gw4;
					 tampon[12] = 0x0F; tampon[13] = 0xD2; // Port 4050
					 ecrt_fram(14, tampon, 0x0A, 0x22);
					}
					else // BP_reset non pressse : Recuperation de la derniere configuration en F-RAM.
						{o = lect_config_des_PGA_en_fram();
						 if (o == 0)
						 	 {for(o=0; o<24; o++) lect_intitule_une_voie_en_fram(o);
						 	  lect_fram(14, tampon, 0x0B, 0x22);
						 	  ip1 = tampon[0]; ip2 = tampon[1]; ip3 = tampon[2]; ip4 = tampon[3];
						 	  masq1 = tampon[4]; masq2 = tampon[5]; masq3 = tampon[6]; masq4 = tampon[7];
						 	  gw1 = tampon[8]; gw2 = tampon[9]; gw3 = tampon[10]; gw4 = tampon[11];
						 	  port_tcpudp = tampon[12];
						 	  port_tcpudp<<=8;
						 	  port_tcpudp&=0xFF00;
						 	  port_tcpudp+=tampon[13];
						 	 }
						}

    init_w5100(); // Initialisation du module WIZNET

    i = 4;
    // Tous les 100 ms, my_alarm_callback est lancee
	// Le dernier argument est un conexte pouvant etre passe a my_alarm_callback(). Non utilise ici.
	// Le 4 affecte a i est certainement un reste de test et est bidon.
    alt_alarm_start (&alarm, 100, my_alarm_callback, &i);


	// Ouverture de la socket 2 cliente UDP. Je me rends compte que le port n'est pas vraiment parametrable...
    if (open_sock(2, 0x02, 4050) == 1) {if DBG printf("Erreur sur open_sock(2, 0x02, 4050).\n");
    			 	  					}

    rang_pga = 40; // Voir protocole.    

	// Envoi continu de la configuration des PGA2505 au module de scene. Un PGA par iteration.
	// Interpretation des commandes issues de MNcontrol.
	// Envoi d'une trame d'etat si un changement d'etat a ete constate dans my_alarm_callback().
	// Traitement des evenements autour de la socket 1.
    while( 1 ) 
    {   // Preparation de la configuration d'un PGA
		lm1 = (0x65 << 24) & 0xFF000000;
        lm2 = (rang_pga << 24) & 0xFF000000;
        lm2+=0xA6;

        lm2+=donnees4PGA[((rang_pga - 40)>>1) & 0x7F].tout_a_la_fois << 8;        

    	IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO1_BASE, lm1);
    	IOWR_ALTERA_AVALON_PIO_DATA(NM_PIO2_BASE, lm2);
    	rang_pga++;
    	
    	if (rang_pga == 88) rang_pga = 40;

		interruption_w5100(); 	// Traitement d'une eventuelle demande d'attention demandee par le WIZNET via
								// sa ligne /INT. Certes, on fonctionne par scrutation (polling).
								// Le processeur "tourne vite" et ainsi, pas de conflit sur les ressources.

		if (!etat_sock1.bit_a_bit.b4) // Si la socket 1 n'est pas a l'ecoute, on fait le necessaire.
    	 		{
    	 		if (open_sock(1, 0x01, port_tcpudp) == 1)
    			 	  				if DBG printf("Erreur sur open_sock(1, 0x01, port_tcpudp).\n");
    		 	 }

		/* Timeout de duree de connexion sur la socket 1 */
		if ((!delai_wd_cnx_sock1) && (etat_sock1.bit_a_bit.b0))
							{close_sock(1);
    	 	  				 }

		if (etat_sock1.bit_a_bit.b1) // Donnees reçues sur la socket 1 ?
    		 			{etat_sock1.bit_a_bit.b1 = 0;
    			 		 depuis_sock1(tampon);

    			 		 switch(tampon[2]) // Demande d'envoi de la configuration des 24 PGA.
							{case 0x01:  flag_divers.bit_a_bit.b1 = 1;
										 flag_divers.bit_a_bit.b2 = 1;
										 o2 = 2;
										 for(o=0; o<24; o++)
												 {tampon[o2]= donnees4PGA[o].tout_a_la_fois>>8;
												  o2++;
												  tampon[o2]= donnees4PGA[o].tout_a_la_fois;
												  o2++;
												 }
										break;

							 case 0x02: // Reception de la configuration d'un PGA
										donnees4PGA[tampon[3]].tout_a_la_fois = (tampon[4] << 8) & 0xFF00;
										donnees4PGA[tampon[3]].tout_a_la_fois+=tampon[5];
										write_config_un_PGA_en_fram(tampon[3]);
										usleep(30000);
										break;

							 case 0x03: // Demande de l'intitule d'une voie.
										strcpy((char *) &tampon[2], intitules_voies[tampon[3]]);
							 	 	 	break;

							 case 0x04: // Reception de l'intitulé d'une voie.
										strcpy(intitules_voies[tampon[3]], (char *) &tampon[4]);
										write_intitule_une_voie_en_fram(tampon[3]);
										break;
							 case 0x05: // Demande d'envoi d'une trame d'etat sur la socket 2.
										flg_envoi_etat = 1;
							 	 	 	break;
							 case 0x06: // Reception de parametres de configuration.
										if ((tampon[3] == 0) && (tampon[4] == 0) && (tampon[5] == 0) && (tampon[6] == 0))
							 	 	 	 	 	 {ecrt_fram(2, &tampon[7], 0x0A, 0x2E); // Memorisation du port
							 	 	 	 	 	 }
							 	 	 	 	 	 else
							 	 	 	 	 	 {
												 switch (tampon[8])
													{case 0: // Remise des 24 PGA en configuration par defaut.
															 for(rang_pga=0; rang_pga<24; rang_pga++) donnees4PGA[rang_pga].tout_a_la_fois = INIT_PGA;
															  write_config_des_PGA_en_fram();
															  break;
													 case 1: // Remise des intitules de voies en appellation par defaut.
															 for(o=0; o<24; o++)
																	 {
																	 strcpy(intitules_voies[o], intitules_voies_origine[o]);
																	 write_intitule_une_voie_en_fram(o);
																	 }
															 break;
													 case 2: ecrt_fram(4, &tampon[3], 0x0A, 0x22); // Memorisation de l'IP
													 	 	 break;
													 case 3: ecrt_fram(4, &tampon[3], 0x0A, 0x26); // Memorisation du masque
													 		 break;
													 case 4: ecrt_fram(4, &tampon[3], 0x0A, 0x2A); // Memorisation de la passerelle
													 		 break;
													}
							 	 	 	 	 	 }
							 			break;
										}

    			 		tampon[0] = 'O'; // Quelque soit la commande, on retourne toujours 64 octets
    			 		tampon[1] = 'K'; // dont les 2 premiers sont 'O' et 'K'.
    			 		while (espace_dispo_TX_sock(1) < 64); // Y'a t'il la place pour envoyer 64 octets sur la socket 1 ?
    			 		vers_sock(1, 64, tampon); // Envoi sur la socket 1.
    			 		close_sock(1);
    	 				}

		// Mise a jour des des infos (IP et PORT) de la socket 2 a partir des infos du client connecte sur la socket 1.
		if (flag_divers.bit_a_bit.b1 == 1)
   	  			{get_info_sock_distante(1, &dip_1, &dip_2, &dip_3, &dip_4, &m);
   	  			 put_info_sock_distante(2, dip_1, dip_2, dip_3, dip_4, port_tcpudp);
   	 	  	 	 spi_lect(6, 0x0406+0x100* 1, pilote_w5100);
    			 spi_ecrt(6, 0x0406+0x100* 2, pilote_w5100);
    			 flag_divers.bit_a_bit.b1 = 0;
    			 }

		if (flag_divers.bit_a_bit.b2  && flg_envoi_etat) // Envoi d'une trame d'etat sur la socket 2
       	 	{flg_envoi_etat = 0;
       	 	 for(i=0; i<8; i++) tampon[i] = trame_etat[i];
       	 	 while (espace_dispo_TX_sock(2) < 64);
       	 	 vers_sock(2, 64, tampon);
       	 	 }
    	}

    return 0; // N'est jamais atteint.
	}

