// UTS 2000 - Fichier 'tdv.cpp' Lecture des variables pour la table de vérite dans le fichier de configuration, et gestion de cette table
// V3.5  Le 01/01/2014
// 
// Pour commander les servo, les nouvelles commandes pouvant être configurées dans le fichier 'config.txt' sont :
// '=val',  Dans une équation 'equ:' si le test est ok '=val <var> valeur' alors <var>=valeur.
//          Exemple : equ: l in_23 =val var_45 789 (met 789 dans la variable n°45 si l'entrée n°23 = 1).
// '=var',  Dans une équation 'equ:' si le test est ok '=var <var> <var2>' alors <var>=contenu de <var2>.
//          Exemple : equ: l in_23 =var var_45 var_46  (copie la valeur de la variable n°46 dans la variable n°45 si l'entrée n°23 = 1).
// '=varx4',  Dans une équation 'equ:' si le test est ok '=varx4 <var> <var2>' alors <var>= 4 fois le contenu de <var2>.
//          Exemple : equ: l in_23 =varx4 var_45 can_0  (copie la valeur de l'entrée can_0 multiplié par 4 dans la variable n°45 si l'entrée n°23 = 1). 
//          Cela sert à commander un servo-moteur(0-1023) par une entrée CAN(0-255).
// Les variables peuvent être positives ou négatives. Il est conseillé de ne pas dépasser -25000 et +25000.
//
/*****************************************************************************/
/* Début TDV                                                                 */
/*****************************************************************************/
#include  <windows.h>
#include  <string.h>
#include  <stdlib.h>
#include  <stdio.h>
#include "Train_UTS.h"
#include  "tdv.h"

#define _CRT_SECURE_NO_WARNINGS  // Limite les messages de warning dans Visual C++

// Déclaration des fonctions externes
extern void EasyTextOut(int, int, char*);
extern void EasyLine(int, int, int, int);
extern void bmp_SetTextColor(int no_color);
extern int pio_set_val(int ,int);
extern int pio_get_val(int);
extern int pio_get_val_(int);
extern int pio_var_int2ch(int ,char []);
extern int pio_define_convert(char [],char []);
extern int pio_var_ch2int(char []);
extern int pio_var_ch2int_(char []);

// Déclaration des variables externes
extern HBRUSH  bmp_pinceau_blanc, bmp_pinceau_gris192, bmp_pinceau_gris220, bmp_pinceau_vert, bmp_pinceau_jaune, bmp_pinceau_orange, bmp_pinceau_vertfonce;
extern HDC   hMemDC;
extern HFONT bmp_fonte;
extern HPEN  bmp_stylo_noir, bmp_stylo_gris128, bmp_stylo_gris192, bmp_stylo_blanc, bmp_stylo_jaune ;
extern int screen_mode;
extern int pio_tdv_on_off[NB_TDV]; // Table de vérité en fonction si =1.
extern int pio_tdv_ind[NB_TDV+1];    // Vadidité d'un table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
extern int pio_exe[NB_EXE];
extern int pio_var[NB_VAR];
extern int pio_var_add_indice; //remplacer var par tab
extern int pio_pulse_cmd[NB_PULSE];
extern int pulse_tab[NB_PULSE][10]; // on w1 a1 w2 a2 w3 out1 out2 (phase tempo)
extern int pulse_no;
extern int tdv_deb;	// Sur la page débug, numero de la premiere table de vérité à afficher.
//extern int pio_define_next_ind;
//extern int pio_define_next_entry;
extern int x_mouse,y_mouse,touche,touche_char,x_mouse_move,y_mouse_move, screen_mode_retour;


int pio_tab[NB_TAB];


cTdv      tdv;
/*****************************************************************************/
/* TDV                                                                       */
/*****************************************************************************/
/* ex:
#tdv
[
	tdv:   0
	on:    1
	in:    det_0 det_1
	init:  clear out_0  clear out_1 clear out_2  #0:r 1:j 2:v
	eq:    1 X   set out_0
	eq:    0 1   set out_1
	eq:    0 0   set out_2
	tdv:   1
	on:    1
	in:    det_0 det_1 out_0  clear io_out_1 clear io_out_2  #0:r 1:j 2:v
	eq:    1     X     1            0              0
	eq:    0     1     0            1              0
	eq:    0     0     0            0              1
	pulse0:4-10-4-10-0
	eq: l[n] v a|o|x[n] =|=set|=clr v
	l|a|o|x[n]tst v ==|<=|>=|<|>|<>  v|cst
	l can_0<20 a det_0 = out_3 = tco=5
	l det_0 = led_0
	l in_0 = aig_cmd_0
	...
]*/


//
cTdv::cTdv(void) { }

// Sous programme de lecture du fichier 'Config.txt' à la recherche de la zone '#tdv'.
//
//
void cTdv::init(char filename[])
{
	FILE* pf;
	char ch[CHAR_CONFIG_NB];
	char ch_error[250];
	char c;
	int no,on=1;
	int phase;
/*  int nb_in,nb_out; */
	int i;
	int val=-1;
	int t;
	int ligne_verif;
	char* pt;
	int num;
	no=-1;
	pio_var_add_indice=0;						// Si l'on relit plusieurs fois 'config.txt', il faut remettre le compteur à 0.
	// pio_tdv_ind[NB_TDV+1] pour vérifier que l'on est à la fin d'une tdv, même si c'est la 50°.
	for(i=0; i<NB_TDV+1; i++) pio_tdv_ind[i]=-1;	// Vadidité d'un table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
	for(i=0; i<NB_TDV; i++) pio_tdv_on_off[i]=0;	// Table de vérité en fonction si =1.
	pulse_no=-1;
	for (i=0; i<NB_PULSE; i++) { pulse_tab[i][0]=0; pulse_tab[i][1]=-1; pulse_tab[i][5]=-1; pulse_tab[i][6]=-1; pulse_tab[i][7]=-1; pulse_tab[i][8]=0; }
	if((pf=fopen(filename,"rt"))==NULL) {
		MessageBox(NULL,"Impossible d'ouvrir le fichier de configuration des tables de vérité 'Config.txt'","Erreur",MB_OK|MB_ICONERROR); exit(1);
	}
	pio_tab[pio_var_add_indice++]=30000+0;
	while(fscanf(pf,"%s%*[^\n]\n",ch)!=EOF) {	// " %s" => "%s%*[^\n]\n" = Nouvelle formule au 02/03/2012, lit uniquement le permier mot de chaque ligne.
		if(STR_SAME strcmp(ch,"#tdv")) { // ch[0]='#',ch[1]='t',ch[2]='d',ch[3]='v', Début de la table de vérité.
			fscanf(pf," %s",ch); // Supprime le caractère '['.
			ligne_verif=1;
			while (ligne_verif==1) {
				if (fscanf(pf," %s",ch)==EOF) break;	// Fin du fichier atteint.
				if (ch[0]=='@') { // La suite de la ligne sont des commentaires jusqu'à la fin de ligne ='\n'.
					do { if (fscanf(pf,"%c",&c)==EOF) break; } while(c!='\n');
					continue;
				}
//
// La zone #tdv contient des directives :
//   - 'tdv:' pour décrire une table de vérité. (on pass en mode phase='TDV_START' dans le programme).
//   - 'equ:' pour décrire une équation indépendante. (on pass en mode phase='TDV_EQU' dans le programme).
//
				if(ch[0]==']') break; // Fin de la zone '#tdv'.
				strlwr(ch);	// Converti la chaine en minuscules.
//MessageBox(NULL,ch,"Chaine",MB_OK|MB_ICONERROR);
//if(phase==TDV_EQU) MessageBox(NULL,ch,"TDV Chaine",MB_OK|MB_ICONERROR);

				if(!strcmp(ch,"tdv:")) { // Indicateur de début d'une table de vérité.
					no++;
					//fscanf(pf," %d",&no);
					pio_tdv_ind[no]=pio_var_add_indice; // Vadidité d'une table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
					pio_tdv_on_off[no]=1; // Table de vérité en fonction si =1.
					phase=TDV_START;
				}
				else if(!strcmp(ch,"equ:"))  // Indicateur de début d'une équation.
					phase=TDV_EQU; // Si on est dans une équation + va à la fin de la boucle directement.

				else if(!strcmp(ch,"on:"))  { fscanf(pf," %d",&on); pio_tdv_on_off[no]=on; } // Table de vérité en fonction si =1.
				else if(!strcmp(ch,"in:"))  { phase=TDV_IN;   pio_tab[pio_var_add_indice++]=30000+1; } //nb_in=0;
				else if(!strcmp(ch,"out:")) { phase=TDV_OUT;  pio_tab[pio_var_add_indice++]=30000+5; } //nb_out=0;
				else if(!strcmp(ch,"init:")){ phase=TDV_INIT; pio_tab[pio_var_add_indice++]=30000+2; } 
				else if(!strcmp(ch,"eq:"))  { phase=TDV_EQ;   pio_tab[pio_var_add_indice++]=30000+3; }
				else if(!strcmp(ch,"clear") || !strcmp(ch,"clr")) {val=TDV_CLR;}
				else if(!strcmp(ch,"set"))  { val=TDV_SET; }
				else if(!strcmp(ch,"0")){                     pio_tab[pio_var_add_indice++]=0; }
				else if(!strcmp(ch,"1")){                     pio_tab[pio_var_add_indice++]=1; }
				else if(!strcmp(ch,"x")){ if (phase==TDV_EQU) pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_X;
					                      else                pio_tab[pio_var_add_indice++]='x';	}
				else if(!strcmp(ch,"|")){ }
				else if(!strncmp(ch,"pulse",5)){
					pt=&ch[5];
					if (atoi(pt)>=0 && atoi(pt)<NB_PULSE ) {
						pulse_no=atoi(pt); pulse_tab[pulse_no][0]=1; pt=pt+2;  if(pulse_no>=10) pt++;  if(pulse_no>=100) pt++;  if(pulse_no>=1000) pt++;
						t=atoi(pt);        pulse_tab[pulse_no][1]=t; pt=pt+2;  if(t>=10) pt++;  if(t>=100) pt++;  if(t>=1000) pt++;
						t=atoi(pt);        pulse_tab[pulse_no][2]=t; pt=pt+2;  if(t>=10) pt++;  if(t>=100) pt++;  if(t>=1000) pt++;
						t=atoi(pt);        pulse_tab[pulse_no][3]=t; pt=pt+2;  if(t>=10) pt++;  if(t>=100) pt++;  if(t>=1000) pt++;
						t=atoi(pt);        pulse_tab[pulse_no][4]=t; pt=pt+2;  if(t>=10) pt++;  if(t>=100) pt++;  if(t>=1000) pt++;
						t=atoi(pt);        pulse_tab[pulse_no][5]=t;
						if (pulse_tab[pulse_no][1]<0 || pulse_tab[pulse_no][2]<0 || pulse_tab[pulse_no][3]<0 || pulse_tab[pulse_no][4]<0 || pulse_tab[pulse_no][5]<0 ) ligne_verif=2;
						else phase=TDV_PULSE;
					}
					else ligne_verif=2;
				}
				else if(!strcmp(ch,"l"))    pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_L;
				else if(!strcmp(ch,"a"))    pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_A;
				else if(!strcmp(ch,"o"))    pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_O;
				//else if(!strcmp(ch,"x"))  pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_X; //reporte dans x
				else if(!strcmp(ch,"ln"))   pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_L+EQ_INV;
				else if(!strcmp(ch,"an"))   pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_A+EQ_INV;
				else if(!strcmp(ch,"on"))   pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_O+EQ_INV;
				else if(!strcmp(ch,"xn"))   pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_X+EQ_INV;
				else if(!strcmp(ch,"="))    pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGA;
				else if(!strcmp(ch,"=set")) pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGASET;
				else if(!strcmp(ch,"=clr")) pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGACLR;
				else if(!strcmp(ch,"=num")) 
					pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGANUM;
				else if(!strcmp(ch,"=val")) 
					pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGAVAL;
				else if(!strcmp(ch,"=var")) 
					pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGAVAR;
				else if(!strcmp(ch,"=varx4")) 
					pio_tab[pio_var_add_indice++]=EQ_BASE+EQ_EGAVARX4;

				else if(pt=strstr(ch,"==")){	// recherche la sous chaine dans la chaine, retourne un pointeur au début de cette sous-chaine.
					num=atoi(pt+2);  // num contient la valeur numérique
					pt='\0';         // ch contient le nom
					pio_var_add_indice--; //modify order
					pio_tab[pio_var_add_indice++]+=EQ_TSTEGA;
					pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);
					pio_tab[pio_var_add_indice++]=num;
				}
				else if(pt=strstr(ch,"<>")){
					num=atoi(pt+2);  // num contient la valeur numérique
					pt='\0';         // ch contient le nom
					pio_var_add_indice--; //modify order
					pio_tab[pio_var_add_indice++]+=EQ_TSTDIFF;
					pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);
					pio_tab[pio_var_add_indice++]=num;
				}
				else if(pt=strstr(ch,"<=")){
					num=atoi(pt+2);  // num contient la valeur numérique
					pt='\0';         // ch contient le nom
					pio_var_add_indice--; //modify order
					pio_tab[pio_var_add_indice++]+=EQ_TSTINFEGA;
					pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);
					pio_tab[pio_var_add_indice++]=num;
				}
				else if(pt=strstr(ch,">=")){
					num=atoi(pt+2);  // num contient la valeur numerique
					pt='\0';         // ch contient le nom
					pio_var_add_indice--; //modify order
					pio_tab[pio_var_add_indice++]+=EQ_TSTSUPEGA;
					pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);
					pio_tab[pio_var_add_indice++]=num;
				}
				else if(pt=strstr(ch,"<")){
					num=atoi(pt+1);  // num contient la valeur numerique
					pt='\0';         // ch contient le nom
					pio_var_add_indice--; //modify order
					pio_tab[pio_var_add_indice++]+=EQ_TSTINF;
					pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);
					pio_tab[pio_var_add_indice++]=num;
				}
				else if(pt=strstr(ch,">")){
					num=atoi(pt+1);  // num contient la valeur numerique
					pt='\0';         // ch contient le nom
					pio_var_add_indice--; //modify order
					pio_tab[pio_var_add_indice++]+=EQ_TSTSUP;
					pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);
					pio_tab[pio_var_add_indice++]=num;
				}
//variable sans set ni clear
				else{
					if( phase==TDV_PULSE){
						//MessageBox(NULL,ch,"debug",MB_OK);
						if (pulse_tab[pulse_no][6]==-1) { 
							if (pio_var_ch2int(ch)!=-1 ) {
								pulse_tab[pulse_no][6]=pio_var_ch2int(ch);  // Converti 'in_102' en '902' = n° interne au programme
							}
							else ligne_verif=2; // pulse : variable inconne.
						}
						else if (pulse_tab[pulse_no][7]==-1) {
							if (pio_var_ch2int(ch)!=-1 ) {
								pulse_tab[pulse_no][7]=pio_var_ch2int(ch);
							}
							else ligne_verif=2; // pulse : variable inconne.
						}
						else ligne_verif=2; // Pas plus de deux variables par pulse:.
					}
					else if(phase==TDV_EQU){ // On est dans une phase équation ' = var_50 '. On stocke  la variable après conversion en n° interne
						if (pio_tab[pio_var_add_indice-2]==EQ_BASE+EQ_EGAVAL) { // 
							 pio_tab[pio_var_add_indice++]=atoi(ch); }			// Si on est dans le cas '=val', on inscrit directement la valeur dans le tableau.
						else pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch);	// Si on est dans le cas '=var' ou '=num', on inscrit le n° interne de variable dans le tableau.
					}
					else{ 
						if(val==-1 && phase==TDV_EQ)   val=TDV_SET;
						if(val==-1 && phase==TDV_INIT) val=TDV_CLR;
						if(phase==TDV_EQ || phase==TDV_INIT)
						{
							if(val==TDV_SET) pio_tab[pio_var_add_indice++]='s';
							else             pio_tab[pio_var_add_indice++]='c';
						}
						pio_tab[pio_var_add_indice++]=pio_var_ch2int(ch); // Converti 'in_102' en '902' = n° interne au programme
						val=-1;
					}
				}
			} //fin while 1
			if (ligne_verif!=1) { // Erreur ou on n'a pas trouvé de signification sur la chaine de caractères analysée. On sort pour ne pas boucler ici.
				strcpy(ch_error,"Fichier 'config.txt',    Section #tdv\n\nErreur de description sur une ligne ou un élement de ligne :\n\n");
				if (ligne_verif==2) strcat(ch_error,"Erreur dans une ligne 'pulse:'\n\n");
				strcat(ch_error,ch);
				MessageBox(NULL,ch_error,"UTS - Erreur",MB_OK|MB_ICONERROR); 	exit(1);
			}
		}     //fin #tdv
	}         //fin ch
	pio_tab[pio_var_add_indice++]=30000+4; //30004 = fin du tableau pio_tab[].
	fclose(pf);
}


// Sous-programme de calcul des équations décrites en table dé vérité. 
// Activé à chaque 'TICK'
//
//
void cTdv::tick(void)
{
	int i,j;
	int nb_in,nb_out;
	int ind;
	int sens,val,ok;
	int test,test2;
	int tab_in[NB_TAB_IN];		// NB_TAB_IN  = Nombre de variables maximum en entrées de table de vérité ou d'équation.
	int tab_out[NB_TAB_OUT];	// NB_TAB_OUT = Nombre de variables maximum en sorties de table de vérité ou d'équation.
	char ch_error[200];			// En cas d'anomalie, texte du message d'erreur.

/*
pulseY:xx-xx-xx-xx-xx var_1 var_2

pio_pulse_cmd[i]= 1 = > Demande d'impulsion, imédiatement remise à 0 au début de 'attente 1'.

pulse_tab[i][0] = 1 => Pulse valide
pulse_tab[i][1] = xx => attente 1 en ticks
pulse_tab[i][2] = xx => actif 1
pulse_tab[i][3] = xx => attente 2
pulse_tab[i][4] = xx => actif 2
pulse_tab[i][5] = xx => attente 3
pulse_tab[i][6] = var_1 => variables à activer
pulse_tab[i][7] = var_2
pulse_tab[i][8] = Etat de l'impulsion de 1 à 5 => attente 1 à attente 3.
pulse_tab[i][9] = Pour chaque état, temporisation en ticks à décompter. Si !=0 l'impulsion est en cours
*/

	for (i=0; i<NB_PULSE; i++) {
		if (pulse_tab[i][0]==1) { // Pulse: valide ?
			if (pulse_tab[i][8]==0) {
				if (pio_pulse_cmd[i]==1) { // Non déclenchée + Action d'impulsion demandé.
					pio_pulse_cmd[i]=0; pulse_tab[i][8]=1;
					pulse_tab[i][9]=pulse_tab[i][1];
				}
			}
			if (pulse_tab[i][8]==1) { // attente 1
				if (pulse_tab[i][9]==0) {
					pulse_tab[i][8]=2; pulse_tab[i][9]=pulse_tab[i][2];
					if (pulse_tab[i][2]) {
						val=pulse_tab[i][6]; if (val!=-1) pio_set_val(val,1);
						val=pulse_tab[i][7]; if (val!=-1) pio_set_val(val,1);
					}
				}
				else pulse_tab[i][9]--;
			}
			if (pulse_tab[i][8]==2) { // actif 1
				if (pulse_tab[i][9]==0) {
					pulse_tab[i][8]=3; pulse_tab[i][9]=pulse_tab[i][3];
					if (pulse_tab[i][2]) {
						val=pulse_tab[i][6]; if (val!=-1) pio_set_val(val,0);
						val=pulse_tab[i][7]; if (val!=-1) pio_set_val(val,0);
					}
				}
				else pulse_tab[i][9]--;
			}
			if (pulse_tab[i][8]==3) { // attente 2
				if (pulse_tab[i][9]==0) {
					pulse_tab[i][8]=4; pulse_tab[i][9]=pulse_tab[i][4];
					if (pulse_tab[i][4]) {
						val=pulse_tab[i][6]; if (val!=-1) pio_set_val(val,1);
						val=pulse_tab[i][7]; if (val!=-1) pio_set_val(val,1);
					}
				}
				else pulse_tab[i][9]--;
			}
			if (pulse_tab[i][8]==4) { // actif 2
				if (pulse_tab[i][9]==0) {
					pulse_tab[i][8]=5; pulse_tab[i][9]=pulse_tab[i][5];
					if (pulse_tab[i][4]) {
						val=pulse_tab[i][6]; if (val!=-1) pio_set_val(val,0);
						val=pulse_tab[i][7]; if (val!=-1) pio_set_val(val,0);
					}
				}
				else pulse_tab[i][9]--;
			}
			if (pulse_tab[i][8]==5) { // attente 3
				if (pulse_tab[i][9]==0)  { pulse_tab[i][8]=0; }
				else pulse_tab[i][9]--;
			}
		}
	}

	// 
	for (i=0;i<NB_TDV;i++) if (pio_tdv_ind[i]!=-1) if (pio_tdv_on_off[i]) {  // Table de vérité en fonction si =1.
		ind=pio_tdv_ind[i]; // Validité d'une table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
		while ((val=pio_tab[ind])!=30004 && ind!=pio_tdv_ind[i+1]) { // 30004 = Fin du tableau pio_tab[] ou fin de la tdv en cours.
//		while((val=pio_tab[ind])!=30004) { // 30004 = Fin du tableau pio_tab[] ou fin de la tdv en cours.
			ind++;
			if(val==30001) /*IN*/ {
				nb_in=0; nb_out=0;
				while((val=pio_tab[ind])<30000) {
					tab_in[nb_in++]=pio_get_val(val);
					ind++;
				}
				if (nb_in>NB_TAB_IN) {
					sprintf(ch_error,"Erreur, une ligne dans une table n°xxx de la section 'tdv:' du fichier 'config.txt'\ncontient plus de  %d  variables d'entrées.",NB_TAB_IN);
					MessageBox(NULL,ch_error,"UTS - Erreur",MB_OK|MB_ICONERROR); exit(1);
				}
			}
			else if (val==30005) { /*OUT*/
				nb_out=0;
				while ((val=pio_tab[ind])<30000) {
					tab_out[nb_out++]=val;
					ind++;
				}
				if (nb_out>NB_TAB_OUT) {
					sprintf(ch_error,"Erreur, une ligne dans une table n°xxx de la section 'tdv:' du fichier 'config.txt'\ncontient plus de  %d  variables de sorties.",NB_TAB_OUT);
					MessageBox(NULL,ch_error,"UTS - Erreur",MB_OK|MB_ICONERROR); exit(1);
				}
			}
			else if (val==30002) { /*INIT*/
				nb_in=nb_out=0;
				while ((sens=pio_tab[ind])<30000) {
					ind++;
					val=pio_tab[ind];
					if (sens=='s') pio_set_val(val,1); else pio_set_val(val,0);
					ind++;
				}
			}
			else if (val==30003) { /*EQ*/
				ok=1;
				for (j=0; j<nb_in; j++) {
					if (pio_tab[ind+j]=='x' || pio_tab[ind+j]==tab_in[j]) ok=ok; else ok=0;
				}
				ind+=nb_in;
				if (ok) {
					for (j=0; j<nb_out; j++) {
						if (pio_tab[ind+j]==0) pio_set_val(tab_out[j],0);
						if (pio_tab[ind+j]==1) pio_set_val(tab_out[j],1);
					}
				}
				ind+=nb_out;
				while ((sens=pio_tab[ind])<30000) {
					ind++;
					val=pio_tab[ind];
					if(ok) { 
						if(sens=='s') pio_set_val(val,1); else pio_set_val(val,0); 
					}
					ind++;
				}
			}
		} //fin while
	} // fin de parcours pour les tables de vérité à 'on'.

	// Parcours la table de vérité à la recherche d'équation de type 'equ:'.
 	ind=0; test=0; test2=0;
	while((val=pio_tab[ind++])!=30004) { // 30004 = Fin du tableau pio_tab[].
		if(val==(EQ_BASE+EQ_L))				{  test=0; if(pio_get_val(pio_tab[ind++])!=0) test=1; }						// LOAD
		else if(val==(EQ_BASE+EQ_O)) 		{ test2=0; if(pio_get_val(pio_tab[ind++])!=0) test2=1; test=test|test2; }	// OR
		else if(val==(EQ_BASE+EQ_A))     	{ test2=0; if(pio_get_val(pio_tab[ind++])!=0) test2=1; test=test&test2; }	// AND
		else if(val==(EQ_BASE+EQ_X))       	{ test2=0; if(pio_get_val(pio_tab[ind++])!=0) test2=1; test=test^test2; }	// XOR
		else if(val==(EQ_BASE+EQ_L+EQ_INV))	{  test=0; if(pio_get_val(pio_tab[ind++])==0) test=1; } // Load inverse
		else if(val==(EQ_BASE+EQ_O+EQ_INV))	{ test2=0; if(pio_get_val(pio_tab[ind++])!=0) test2=1; test=test|(test2^1); }
		else if(val==(EQ_BASE+EQ_A+EQ_INV))	{ test2=0; if(pio_get_val(pio_tab[ind++])!=0) test2=1; test=test&(test2^1); }
		else if(val==(EQ_BASE+EQ_X+EQ_INV))	{ test2=0; if(pio_get_val(pio_tab[ind++])!=0) test2=1; test=test^(test2^1); }
		else if(val==(EQ_BASE+EQ_EGA))     	{ pio_set_val(pio_tab[ind++],test); }
		else if(val==(EQ_BASE+EQ_EGASET))  	{ if(test==1) pio_set_val(pio_tab[ind++],1); }
		else if(val==(EQ_BASE+EQ_EGACLR))  	{ if(test==1) pio_set_val(pio_tab[ind++],0); }
		else if(val==(EQ_BASE+EQ_EGANUM))  	{ pio_set_val(pio_tab[ind],pio_tab[ind+1]); ind+=2; }
		else if(val==(EQ_BASE+EQ_EGAVAL)) 	{ if (test==1) pio_set_val(pio_tab[ind],pio_tab[ind+1]); ind+=2; }
		else if(val==(EQ_BASE+EQ_EGAVAR))  	{if(test==1) pio_set_val(pio_tab[ind],  pio_get_val(pio_tab[ind+1])); ind+=2;} 
		else if(val==(EQ_BASE+EQ_EGAVARX4))	{if(test==1) pio_set_val(pio_tab[ind],4*pio_get_val(pio_tab[ind+1])); ind+=2;} 
		else if(val==(EQ_BASE+EQ_TSTEGA))	{ test=0; if(pio_get_val(pio_tab[ind])==pio_tab[ind+1]) test=1; ind+=2; }		// VAR == val
		else if(val==(EQ_BASE+EQ_TSTDIFF))	{ test=0; if(pio_get_val(pio_tab[ind])!=pio_tab[ind+1]) test=1; ind+=2;	}		// VAR <> val
		else if(val==(EQ_BASE+EQ_TSTSUP))	{ test=0; if(pio_get_val(pio_tab[ind])> pio_tab[ind+1]) test=1; ind+=2;}		// VAR >  val
		else if(val==(EQ_BASE+EQ_TSTSUPEGA)){ test=0; if(pio_get_val(pio_tab[ind])>=pio_tab[ind+1]) test=1; ind+=2;}		// VAR >= val
		else if(val==(EQ_BASE+EQ_TSTINF))	{ test=0; if(pio_get_val(pio_tab[ind])< pio_tab[ind+1]) test=1; ind+=2;}		// VAR <  val
		else if(val==(EQ_BASE+EQ_TSTINFEGA)){ test=0; if(pio_get_val(pio_tab[ind])<=pio_tab[ind+1]) test=1; ind+=2;}		// VAR <= val
		else {}
	}
}

// Sous-Programme optionnel d'écriture dans le fichier 'debug_prog.txt' pour trace.
//
//
void cTdv::save_conf(void)
{
	FILE* pf;
	int i,j;
	if((pf=fopen("debug_prog.txt","wt"))==NULL) {
		MessageBox(NULL,"Impossible de créer le fichier 'Debug_prog.txt'","Erreur",MB_OK|MB_ICONERROR); exit(1);
	}
	fprintf(pf,"\n\nPIO_VAR\n");
	for(i=0;i<pio_var_add_indice;i++) fprintf(pf,"\n%4d: %4d  %c",i,pio_tab[i],pio_tab[i]);
	fprintf(pf,"\n\nPIO_ON_OFF\n");
	for(i=0;i<NB_TDV;i++) fprintf(pf,"\n%4d: %4d",i,pio_tdv_on_off[i]); // Table de vérité en fonction si =1.
	fprintf(pf,"\n\nPIO_IND\n");
	for(i=0;i<NB_TDV;i++) fprintf(pf,"\n%4d: %4d",i,pio_tdv_ind[i]); // Validité d'une table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
	for(i=0;i<NB_PULSE;i++) { fprintf(pf,"\n%2d:",i); for(j=0;j<8;j++) fprintf(pf," %4d",pulse_tab[i][j]); }
	fclose(pf);
}


// Affiche un tableau avec le contenu des tables de vérité avec le menu : 'Debug > Tables de vérité'.
//
void cTdv::debug(int action)
{
	static int i,j,k,l,m,x,y,ind,val;
	static int dimy=20; // Dimension vertical d'une cellule
	static int nblignes=25; // Nombre de ligne du tableau (sans le titre)	
	static int decaly=70; //Decalage de la premiére ligne du tableau vers les bas.

	char ch[200];

	SelectObject(hMemDC,bmp_fonte); SetBkMode(hMemDC,TRANSPARENT);
	SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_blanc);

	if (action==DEBUG_TOTAL_PAINT) { // ACTION = REDESSINE TOUTE LA FENETRE.
		Rectangle(hMemDC,0,0,800,700);SelectObject(hMemDC,bmp_stylo_gris192);
		SetTextColor(hMemDC,RGB(0,0,0)); // Texte en noir.
		SelectObject(hMemDC,bmp_pinceau_gris192); SelectObject(hMemDC,bmp_stylo_gris192); Rectangle(hMemDC,800-15,15,800-2,2); // Rectangle gris pour fermer la fenêtre.
		SelectObject(hMemDC,bmp_stylo_noir); EasyLine(800-14,3,800-3,14 ); EasyLine(800-14,13,800-3,2); // Croix noire [X].
		SelectObject(hMemDC,bmp_stylo_noir);  EasyLine(800-2,1,800-2,16); EasyLine(800-16,15,800-1,15); // Trait noir.
		SelectObject(hMemDC,bmp_stylo_gris128); EasyLine(800-3,2,800-3,15); EasyLine(800-15,14,800-2,14); // Trait gris foncé.
		SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);

		EasyTextOut(2, 2,"AFFICHE LA COMPOSITION DES TABLES DE VÉRITÉS       (50 tables maximum)"); EasyTextOut(800-140,2,"(QUITTER = ESC)");
		SelectObject(hMemDC,bmp_stylo_noir); SelectObject(hMemDC,bmp_pinceau_gris220); // Rectangle gris foncé.
		Rectangle(hMemDC,0, decaly+(nblignes)*dimy-1,97, decaly+(nblignes+1)*dimy-3);

		SelectObject(hMemDC,bmp_stylo_gris128);
		EasyLine(1,  decaly+(nblignes+1)*dimy-3-2, 96, decaly+(nblignes+1)*dimy-3-2);  	// Relief rectangle.
		EasyLine(95, decaly+(nblignes)*dimy-1+1,   95, decaly+(nblignes+1)*dimy-3-2);	// Relief rectangle.
		SelectObject(hMemDC,bmp_stylo_noir);

		EasyLine(97-10, decaly+(nblignes+1)*dimy+1-2-4, 97, decaly+(nblignes+1)*dimy+1-4-12);  // Dessine un trait dans l'angle = valeurs modifiables.
		SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);
		EasyTextOut(2,decaly+(nblignes)*dimy+1," CLIC-DROIT :AFFICHE LA TABLE SUIVANTE [1-50]");
		j=0; k=0;
		for(i=0;i<NB_TDV;i++) {
			if (pio_tdv_ind[i]!=-1) j++;   // Vadidité d'une table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
			if (pio_tdv_on_off[i]==1) k++; // Table de vérité en fonction si = 1.
		}
		sprintf_s(ch,"Nombre de tables valides = %d  en fonction = %d",j,k); 
	    EasyTextOut(2,1*dimy+2,ch);
		sprintf_s(ch,"Nombre d'éléments dans toutes les tables et équations = %d (%d éléments maximum)",pio_var_add_indice, NB_TAB); 
		EasyTextOut(2,2*dimy+2,ch);

// Dessine les cases pour accéder directement aux tables.
		EasyTextOut(2,decaly+(nblignes+1)*dimy+1," CLIQUEZ sur une case pour un accès direct à la table n° (rouge=à off):");
		SetTextColor(hMemDC,RGB(0,0,255));	// Texte en bleu
		for (i=0; i<25;i++) { 
			Rectangle(hMemDC, 30*(i+1), decaly+(nblignes+2)*dimy-3, 30*(i+2)+1, decaly+(nblignes+2)*dimy+18);
			if ( pio_tdv_on_off[i]==1 ) { SetTextColor(hMemDC,RGB(0,0,255)); }	// Texte en bleu
			else { SetTextColor(hMemDC,RGB(255,0,0)); }	// Texte en rouge
			sprintf_s(ch,"%2d",i); 
		    if (pio_tdv_ind[i]!=-1) EasyTextOut(30*(i+1)+7,decaly+(nblignes+2)*dimy+1,ch);
			Rectangle(hMemDC, 30*(i+1), decaly+(nblignes+3)*dimy-3, 30*(i+2)+1, decaly+(nblignes+3)*dimy+18);
			if ( pio_tdv_on_off[i+25]==1 ) { SetTextColor(hMemDC,RGB(0,0,255)); }	// Texte en bleu
			else { SetTextColor(hMemDC,RGB(255,0,0)); }	// Texte en rouge
			sprintf_s(ch,"%2d",i+25); 
		    if (pio_tdv_ind[i+25]!=-1) EasyTextOut(30*(i+1)+7,decaly+(nblignes+3)*dimy+1,ch);
		}
	}

	SelectObject(hMemDC,bmp_stylo_gris192);

	if(action==DEBUG_MOUSE) { // ACTION = CLIC GAUCHE DE LA SOURIS
		if ((x_mouse > 0 && x_mouse < 97) && (y_mouse > decaly+nblignes*dimy+1-2 && y_mouse < decaly+(nblignes+1)*dimy+1-4)) { //	Clique dans [CLIC DROIT]
			action=DEBUG_MOUSE_RIGHT; //	Simule le clique-droit traité plus loin.
		}
		else {
			if ((x_mouse > 800-15 && x_mouse < 800-2) && (y_mouse > 2 && y_mouse < 15)) {
				screen_mode= screen_mode_retour; 
				return;	// On ferme la fenêtre.
			}	
			if (y_mouse>=decaly+(nblignes+2)*dimy-3 && y_mouse<=decaly+(nblignes+3)*dimy+18) {
				if (x_mouse>=30 && x_mouse<=30*(24+2)+1) {
					i=(x_mouse-30)/30;
					if (y_mouse>=decaly+(nblignes+3)*dimy-3) i=i+25; // i = 0 à 49 = numéro de tdv.
					if (i<NB_TDV && pio_tdv_ind[i]!=-1) tdv_deb=i;
					SelectObject(hMemDC,bmp_stylo_blanc);
					Rectangle(hMemDC,0,decaly,799,decaly+(nblignes)*dimy-1);
					SelectObject(hMemDC,bmp_stylo_gris192);
				}
			}
		}
	}

	if(action==DEBUG_MOUSE_RIGHT) {    // ACTION = CLIC DROIT DE LA SOURIS, on passe à la table suivante.
		SelectObject(hMemDC,bmp_stylo_blanc);
		Rectangle(hMemDC,0,decaly,799,decaly+(nblignes)*dimy-1);
		SelectObject(hMemDC,bmp_stylo_gris192);
    	tdv_deb++;
		if (pio_tdv_ind[tdv_deb]==-1 || tdv_deb>=NB_TDV) tdv_deb=0;
	}

	if(action==DEBUG_KEY) { }          // ACTION = TOUCHE ENFONCEE

	SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_blanc);
	Rectangle(hMemDC,0,70,800,70+20*25-1);
	SetTextColor(hMemDC,RGB(255,0,0));	// Texte en rouge
	if ( pio_tdv_on_off[tdv_deb]==1 ) { sprintf_s(ch,"Numéro de la table en cours = %d, table à 'ON' ",tdv_deb); }
	else                              { sprintf_s(ch,"Numéro de la table en cours = %d, !!! table à 'OFF' !!! table à 'OFF'!!!",tdv_deb); }
	EasyTextOut(  2,decaly+0*dimy+2,ch);
	EasyTextOut( 20,decaly+1*dimy+2,"Variables initialisées");
	EasyTextOut(250,decaly+1*dimy+2,"Variables d'entrées");
    EasyTextOut(480,decaly+1*dimy+2,"Variables de sorties");

	SetTextColor(hMemDC,RGB(0,0,255));	// Texte en bleu
	SelectObject(hMemDC,bmp_pinceau_blanc);
	SelectObject(hMemDC,bmp_stylo_blanc); // Blanc !
	if ((pio_tdv_ind[tdv_deb]!=-1) && (pio_tdv_on_off[tdv_deb]==1 )) {  // Table de vérité en fonction si =1.
		ind=pio_tdv_ind[tdv_deb];		// Validité d'une table de vérité. -1 = invalide ou indicateur d'offset de cette table dans 'pio_tab[]'.
		while (pio_tab[ind]!=30004 && ind!=pio_tdv_ind[tdv_deb+1] ) {	// 30004 = Fin du tableau pio_tab[].
			val=pio_tab[ind];
			ind++;
			if (val==30002) { // C'est une séquence INIT.
				y=0;
				// Il peut y avoir deux lignes 'init:', on ne sort pas à la fin de la premiere.
				while ((pio_tab[ind]==30002 || (pio_tab[ind]<30000 && y<nblignes)) && ind!=pio_tdv_ind[tdv_deb+1]) { // > 30000 = Fin de la séquence d'init.
					if (pio_tab[ind]==30002) ind++;		// Affiche les noms des variables initialisées  et leurs valeurs.
					val=pio_tab[ind]; // 's' ou 'c' = set ou clear.
					ind++;
					Rectangle(hMemDC,15,decaly-1+(2+y)*dimy,220,decaly+(3+y)*dimy);
					if (val=='s' && y<nblignes) { // =s => 'set'=1.
						pio_var_int2ch(pio_tab[ind],ch);
						EasyTextOut(20,decaly+2+(2+y)*dimy,ch);
						EasyTextOut(180,decaly+2+(2+y)*dimy,"= 1");
					}
					else if (val=='c' && y<nblignes) { // =c => 'clear'=0.
						pio_var_int2ch(pio_tab[ind],ch);
						EasyTextOut(20,decaly+2+(2+y)*dimy,ch);
						EasyTextOut(180,decaly+2+(2+y)*dimy,"= 0");
					}
					ind++;y++;
				}
			}
			if (val==30001) { //IN
				y=0;
				while (pio_tab[ind]<30000 && y<nblignes) {		// Affiche les noms des variables d'entrées et leurs valeurs.
					Rectangle(hMemDC,245,decaly-1+(2+y)*dimy,450,decaly+(3+y)*dimy);
					pio_var_int2ch(pio_tab[ind],ch);                EasyTextOut(250,decaly+2+(2+y)*dimy,ch);
					sprintf_s(ch,"= %d",pio_get_val(pio_tab[ind])); EasyTextOut(410,decaly+2+(2+y)*dimy,ch);
					ind++;y++;
				}
			}
			else if (val==30005) { //OUT
				y=0;
				while (pio_tab[ind]<30000 && y<nblignes) {		// Affiche les noms des variables de sorties et leurs valeurs.
					Rectangle(hMemDC,475,decaly-1+(2+y)*dimy,680,decaly+(3+y)*dimy);
					pio_var_int2ch(pio_tab[ind],ch);                EasyTextOut(480,decaly+2+(2+y)*dimy,ch);
					sprintf_s(ch,"= %d",pio_get_val(pio_tab[ind])); EasyTextOut(640,decaly+2+ (2+y)*dimy,ch);
					ind++;y++;
				}
				break;
			}
		} //fin while
	}
	SelectObject(hMemDC,bmp_stylo_gris192);
 }

// Affiche un tableau avec le contenu des tables de vérité 'pulse:' avec le menu : 'Debug > pulse'.
//
void cTdv::debug2(int action)
{
	int i, j;
	char ch[200], ch2[25] ;	// ch[25] pour contenir 'garage_lock_status_0'+ '/0'
	static int pulse_affiche_deb=0;
	static int dimnx=44;    // Dimension horizontal d'une cellule 'Numéro'
	static int dimcx=68;    // Dimension horizontal d'une cellule
	static int dimy=16;     // Dimension vertical d'une cellule
	static int nblignes=32; // Nombre de ligne du tableau (sans le titre)	
	static int decaly=16;   // Decalage de la premiére ligne vers le bas.
	float nb_secondes;
  
	SelectObject(hMemDC,bmp_fonte); SetBkMode(hMemDC,TRANSPARENT);
	SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);

	if (action==DEBUG_TOTAL_PAINT) {     // ACTION = REDESSINE TOUTE LA FENETRE.
		Rectangle(hMemDC, 0 ,0, 800, 700);
		SelectObject(hMemDC,bmp_pinceau_gris192); SelectObject(hMemDC,bmp_stylo_gris192); Rectangle(hMemDC,800-15,15,800-2,2); // Rectangle gris pour fermer la fenêtre.
		SelectObject(hMemDC,bmp_stylo_noir); EasyLine(800-14,3,800-3,14 ); EasyLine(800-14,13,800-3,2); // Croix noire.
		SelectObject(hMemDC,bmp_stylo_noir);  EasyLine(800-2,1,800-2,16); EasyLine(800-16,15,800-1,15); // Trait noir.
		SelectObject(hMemDC,bmp_stylo_gris128); EasyLine(800-3,2,800-3,15); EasyLine(800-15,14,800-2,14); // Trait gris foncé.
		SelectObject(hMemDC,bmp_pinceau_blanc); SelectObject(hMemDC,bmp_stylo_gris192);
		Rectangle(hMemDC, 0, decaly, 800, decaly+dimy+1); // Titre des colonnes.
		EasyLine(dimnx,         decaly, dimnx,         decaly+dimy);
		EasyLine(dimnx+dimcx,   decaly, dimnx+dimcx,   decaly+dimy);
		EasyLine(dimnx+2*dimcx, decaly, dimnx+2*dimcx, decaly+dimy);
		EasyLine(dimnx+3*dimcx, decaly, dimnx+3*dimcx, decaly+dimy);
		EasyLine(dimnx+4*dimcx, decaly, dimnx+4*dimcx, decaly+dimy);
		EasyLine(dimnx+5*dimcx, decaly, dimnx+5*dimcx, decaly+dimy);
		EasyLine(dimnx+6*dimcx, decaly, dimnx+6*dimcx, decaly+dimy);
		EasyLine(dimnx-10,         decaly+dimy, dimnx,         decaly+dimy-10); // Dessine un trait dans l'angle => valeurs modifiables
		EasyLine(dimnx-10+dimcx,   decaly+dimy, dimnx+dimcx,   decaly+dimy-10);
		EasyLine(dimnx-10+2*dimcx, decaly+dimy, dimnx+2*dimcx, decaly+dimy-10);
		EasyLine(dimnx-10+3*dimcx, decaly+dimy, dimnx+3*dimcx, decaly+dimy-10);
		EasyLine(dimnx-10+4*dimcx, decaly+dimy, dimnx+4*dimcx, decaly+dimy-10);
		EasyLine(dimnx-10+5*dimcx, decaly+dimy, dimnx+5*dimcx, decaly+dimy-10);
		EasyLine(dimnx-10+6*dimcx, decaly+dimy, dimnx+6*dimcx, decaly+dimy-10);
		bmp_SetTextColor(BMP_CST_COLOR_NOIR);			// Texte en noir.
		EasyTextOut(2, 2,"AFFICHE LA COMPOSITION DES TABLES DE VÉRITÉS    Partie 'pulse:'  (32 maximum)"); EasyTextOut(800-140,2,"(QUITTER = ESC)");
		EasyTextOut(2,decaly+(nblignes+2)*dimy+1,"Section '#tdv'+'pulse:'");
		EasyTextOut(2,decaly+(nblignes+3)*dimy,"CLIQUEZ sur une ligne pour activer l'impulsion.");
		EasyTextOut(2,decaly+(nblignes+4)*dimy,"Permet de programmer une série de deux impulsions de durée 'On' sur une ou deux sorties.");
		EasyTextOut(2,decaly+(nblignes+5)*dimy,"Pause, On, Pause, On, Pause = Temps secondes ( = 95msec * nb tick).");

		SelectObject(hMemDC,bmp_pinceau_vert); // Rectangle vert.
		Rectangle(hMemDC, 0, -2+decaly+(nblignes+6)*dimy,96,-1+decaly+(nblignes+7)*dimy);
		SelectObject(hMemDC,bmp_pinceau_blanc);
		EasyTextOut(2,decaly+(nblignes+6)*dimy,"LIGNE VERTE = Impulsion en cours.");

		bmp_SetTextColor(BMP_CST_COLOR_ROUGE); // Texte en rouge.
		EasyTextOut(2,                2+decaly,"  n°"); // Indice 'i' du tableau : descr[i][].
		EasyTextOut(17+dimnx,         2+decaly,"Etat"); //
		EasyTextOut(15+dimnx+dimcx,   2+decaly,"Pause"); //
		EasyTextOut(25+dimnx+2*dimcx, 2+decaly,"On"); //
		EasyTextOut(15+dimnx+3*dimcx, 2+decaly,"Pause"); //
		EasyTextOut(25+dimnx+4*dimcx, 2+decaly,"On"); //
		EasyTextOut(15+dimnx+5*dimcx, 2+decaly,"Pause"); //
		EasyTextOut(10+dimnx+6*dimcx, 2+decaly,"Variables activées par l'impulsion"); // 
	}

	if (action==DEBUG_MOUSE) { // ACTION = CLIC GAUCHE DE LA SOURIS => Actionne l'impulsion.
		if ((x_mouse > 800-15 && x_mouse < 800-2) && (y_mouse > 2 && y_mouse < 15)) {
			screen_mode= screen_mode_retour; 
			return;	// On ferme la fenêtre.
		}
		i=(y_mouse-2*dimy)/dimy; 
		if (y_mouse>=2*dimy && i>=0 && i<nblignes && pulse_affiche_deb+i<NB_PULSE && pulse_tab[pulse_affiche_deb+i][0]==1) {
			pio_pulse_cmd[pulse_affiche_deb+i]=1;	// Lance l'action.
		}
	}

	if (action==DEBUG_MOUSE_RIGHT) { }  // ACTION = CLIC DROIT DE LA SOURIS => Rien.
	if (action==DEBUG_KEY) { }   // ACTION = TOUCHE ENFONCEE => Rien.

	pulse_affiche_deb= 0;	// Valeur de la premiere ligne à afficher.
	bmp_SetTextColor(BMP_CST_COLOR_BLEUF);			// Texte en bleu foncé.
	for (i=0; i<nblignes; i++) {
		if (pulse_affiche_deb+i<NB_PULSE) {
			if (pulse_tab[pulse_affiche_deb+i][0]==1) { SetTextColor(hMemDC,RGB(0,0,255)); }// En bleu pulse valide.
			else  { SetTextColor(hMemDC,RGB(192,192,192)); } // En gris pulse invalide.
			sprintf_s(ch,"%3d",pulse_affiche_deb+i);
			if (pulse_tab[pulse_affiche_deb+i][0]==1 && pulse_tab[pulse_affiche_deb+i][8]!=0) SelectObject(hMemDC,bmp_pinceau_vert); // Ligne verte si pulse en cours.
			else SelectObject(hMemDC,bmp_pinceau_blanc);
			Rectangle(hMemDC, 0, dimy*(i+2), 800, dimy*(i+3)+1);
			EasyLine(dimnx,         dimy*(i+2), dimnx,         dimy*(i+3)+1);
			EasyLine(dimnx+dimcx,   dimy*(i+2), dimnx+dimcx,   dimy*(i+3)+1);
			EasyLine(dimnx+2*dimcx, dimy*(i+2), dimnx+2*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+3*dimcx, dimy*(i+2), dimnx+3*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+4*dimcx, dimy*(i+2), dimnx+4*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+5*dimcx, dimy*(i+2), dimnx+5*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+6*dimcx, dimy*(i+2), dimnx+6*dimcx, dimy*(i+3)+1);
			EasyTextOut(10,2+dimy*(i+2),ch);			// N° d'indice du tableau
			if (pulse_tab[pulse_affiche_deb+i][0]==1) {  // Elément valide ?
				if (pulse_tab[pulse_affiche_deb+i][8]!=0) {
					if (pulse_tab[pulse_affiche_deb+i][8]==2 || pulse_tab[pulse_affiche_deb+i][8]==4) {
						SelectObject(hMemDC,bmp_pinceau_orange); // Rectangle orange si pulse en cours "état haut".
					}
					else {
						SelectObject(hMemDC,bmp_pinceau_vertfonce); // Rectangle vert foncé si pulse en cours "état bas".
					}
					Rectangle(hMemDC, dimnx+pulse_tab[pulse_affiche_deb+i][8]*dimcx, dimy*(i+2), 1+dimnx+(pulse_tab[pulse_affiche_deb+i][8]+1)*dimcx, dimy*(i+3)+1);
					SelectObject(hMemDC,bmp_pinceau_blanc);
					sprintf_s(ch,"%2d",pulse_tab[pulse_affiche_deb+i][8]); // Etat de l'impulsion
					if (pulse_tab[pulse_affiche_deb+i][8]==2 || pulse_tab[pulse_affiche_deb+i][8]==4) {
						strcat (ch," ON");
					}
					else  strcat (ch," OFF");
				EasyTextOut(12+dimnx,2+dimy*(i+2),ch);
				}
				for (j=0; j<5; j++) {
					nb_secondes=(TIMER_PRG+15)*pulse_tab[pulse_affiche_deb+i][j+1];
					nb_secondes=nb_secondes/1000;
					sprintf_s(ch,"%4.1f",nb_secondes); // * temps environ d'une boucle
					EasyTextOut(2+dimnx+13+((j+1)*dimcx),2+dimy*(i+2),ch);
				}
				sprintf_s(ch,"");
				for (j=0; j<2; j++) {
					if (pulse_tab[pulse_affiche_deb+i][j+6]!=-1) {
						pio_var_int2ch(pulse_tab[pulse_affiche_deb+i][j+6],ch2);
						strcat(ch,ch2); strcat(ch,"    ");
					}
				}
				EasyTextOut(10+dimnx+6*dimcx, 2+dimy*(i+2),ch);
			}
		}
		else {
			Rectangle(hMemDC, 0, dimy*(i+2), 800, dimy*(i+3)+1);
			EasyLine(dimnx,         dimy*(i+2), dimnx,         dimy*(i+3)+1);
			EasyLine(dimnx+dimcx,   dimy*(i+2), dimnx+dimcx,   dimy*(i+3)+1);
			EasyLine(dimnx+2*dimcx, dimy*(i+2), dimnx+2*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+3*dimcx, dimy*(i+2), dimnx+3*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+4*dimcx, dimy*(i+2), dimnx+4*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+5*dimcx, dimy*(i+2), dimnx+5*dimcx, dimy*(i+3)+1);
			EasyLine(dimnx+6*dimcx, dimy*(i+2), dimnx+6*dimcx, dimy*(i+3)+1);
		}
	}
}
/*****************************************************************************/
/* Fin TDV                                                                   */
/*****************************************************************************/
