Bonjour à tous,
Je voudrais témoigner ici que la modélisation "objet" de Pierre fonctionne bien !
J’ai donc modélisé mon réseau avec les objets Aiguille et Zone seulement pour commencer.
Cela se passe en 4 étapes :
Etape 1 : les classes prototypes (copier-coller du code de Pierre). J’en ai profité pour ajouter l’action d’envoi des commandes d’aiguille sur le bus CAN, mais cela ne sert pas pour le moment.
///////////// PROTOTYPE CLASSE AIGUILLE ////////////////////
class Aiguille {
private:
byte index; // 0.. MaxAIG-1
boolean etat=true; // directe (true) ou deviee false)
Zone* zone; // la Zone ou est l'aiguille
public:
Aiguille(byte a_index, Zone* z) { // constructeur
index = a_index;
zone=z;
}
boolean directer() { // commande de l'aiguille en position directe
this->etat=true;
output.id = 0x40;
output.length = 1;
output.data.bytes[0] = this->index + 0xC0;
Can0.sendFrame(output);
return true;
}
boolean devier() { // commande de l'aiguille en position déviée
this->etat=false;
output.id = 0x40;
output.length = 1;
output.data.bytes[0] = this->index + 0x80;
Can0.sendFrame(output);
return true;
}
boolean directe() { // demande d'état
return this->etat;
} // méthode utilitaire};
};
////////////////// PROTOTYPE CLASSE ZONE ////////////////////
class Zone {
public:
byte index; // 0.. MaxZone-1
boolean etat; // libre ou occupé
Signal* signalPair;
Signal* signalImpair; // les signaux éventuels de la zone
Zone(byte a_index, Signal* sp, Signal* si) { // constructeur
index = a_index;
signalPair=sp;
signalImpair=si; }
virtual Zone* suivantePaire() { return NULL; } // la zone suivante paire (éventuellement vide)
virtual Zone* suivanteImpaire() { return NULL; } // la zone suivante impaire (éventuellement vide)
virtual void actions() {} // les actions spécifiques à faire en cas d'occupation
virtual void desactions() {} // les actions spécifiques à faire en cas de libération
boolean occupee() { return etat; } // méthode utilitaire
boolean libre() { return !etat; } // méthode utilitaire
void occuper() { // appelée par la rétrosignalisation
// fait tout ce qu'il y a à faire en cas d'occupation (actions communes à toutes les zones)
actions(); // fait les actions spécifiques à une zone
}
void liberer() { // appelée par la rétrosignalisation
// fait tout ce qu'il y a à faire en cas de libération (actions communes à toutes les zones)
desactions(); // fait les actions spécifiques à une zone
}
Zone* selonAiguille(Aiguille* a,Zone* z1,Zone* z2) { return a->directe()?z1:z2; } // méthode utilitaire
};
Etape 2 : je crée toutes mes zones par héritage du prototype (voici seulement les 4 premières, elle sont toutes identiques)////////////// HERITAGES CLASSES ZONES REELLES ////////////////////
// les zones reelles (héritages de Zone)
// 0 gare base loisirs (pair/droite= 1 impair/gauche=0=butoir)
class Z0 : public Zone { // 0 gare base loisirs (pair/droite= 1 impair/gauche=0=butoir)
public:
Z0(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
virtual Zone* suivantePaire();
virtual Zone* suivanteImpaire();
};
// 1 VV centre (pair/droite=2, impair/gauche=0)
class Z1 : public Zone { // 1 VV centre (pair/droite=2, impair/gauche=0)
public:
Z1(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
virtual Zone* suivantePaire();
virtual Zone* suivanteImpaire();
};
// 2 liaison VV-Hor (pair/droite=3siPdroite, impair/gauche=1+aiguillePdevié=4)
class Z2 : public Zone {
public:
Z2(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
virtual Zone* suivantePaire();
virtual Zone* suivanteImpaire();
};
// 3 gare centre (droite/pair=3=butoir, gauche/impair=2)
class Z3 : public Zone {
public:
Z3(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
virtual Zone* suivantePaire();
virtual Zone* suivanteImpaire();
};
etc…
Etape 3 : déclaration des objets réels (zones et aiguilles). Pour accéder individuellement aux objets, à partir des index contenus dans les messages CAN (dans un événement « occupation de zone » par exemple), j’ai déclaré un tableau de zones. De même pour le tableau d’aiguilles.
De cette façon, on ne manipule que des pointeurs sur les zones et les aiguilles.
/////////////////// DECLARATIONS ZONES ////////////////////
// zones
Zone* z0=new Z0(0,NULL,s2);
Zone* z1=new Z1(1,NULL,s2);
Zone* z2=new Z2(2,NULL,NULL);
Zone* z3=new Z3(3,s2,NULL);
Zone* z4=new Z4(4,s2,c2);
Zone* z5=new Z5(5,s2,c2);
Zone* z6=new Z6(6,s2,c2);
Zone* z7=new Z7(7,s2,c2);
Zone* z8=new Z8(8,s2,c2);
Zone* z9=new Z9(9,s2,c2);
etc…
const int MaxZone = 40;
Zone* listez[MaxZone]= {
z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15,
z16, z17, z18, z19, z20, z21, z22, z23, z24, z25, z26, z27, z28, z29, z30,
z31, z32, z33, z34, z35, z36, z37, z38, z39
};
/////////////////// DECLARATIONS AIGUILLES ////////////////////
// aiguilles
Aiguille* a0=new Aiguille(0,z26); //A
Aiguille* a1=new Aiguille(1,z26); //B
Aiguille* a2=new Aiguille(2,z15); //C
Aiguille* a3=new Aiguille(3,z26); //D
Aiguille* a4=new Aiguille(4,z15); //E
Aiguille* a5=new Aiguille(5,z14); //F
Aiguille* a6=new Aiguille(6,z14); //G
Aiguille* a7=new Aiguille(7,z12); //H
Aiguille* a8=new Aiguille(8,z12); //I
Aiguille* a9=new Aiguille(9,z29); //J
Aiguille* a10=new Aiguille(10,z38); //K
Aiguille* a11=new Aiguille(11,z29); //L
Aiguille* a12=new Aiguille(12,z39); //M
Aiguille* a13=new Aiguille(13,z6); //N
Aiguille* a14=new Aiguille(14,z35); //O
Aiguille* a15=new Aiguille(15,z2); //P
Aiguille* a16=new Aiguille(16,z4); //Q
Aiguille* a17=new Aiguille(17,z17); //R
Aiguille* a18=new Aiguille(18,z24); //S
Aiguille* a19=new Aiguille(19,z37); //T TJD demi a5 vers deviation
Aiguille* a20=new Aiguille(20,z37); //U TJD demi a6 vers deviation
const int MaxAig = 21;
Aiguille* listea[MaxAig]= {
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
a12, a13, a14, a15, a16, a17, a18, a19, a20
};
Etape 4 : la modélisation de mon réseau commence maintenant par l’écriture des méthodes particulières « suivantePaire » et « suivanteImpaire »Pour ce faire, j’ai découpé mon réseau en zones. Certaines zones contiennent une aiguille ou plusieurs. J’ai défini le sens Pair (horaire) et Impaire (trigo) pour savoir quelle est la zone suivante paire ou impaire en fonction de la position d’aiguille s’il y en a une à traverser.
J’applique alors la méthode utilitaire du prototype :
selonAiguille(Aiguille* a,Zone* z1,Zone* z2) { return a->directe()?z1:z2; }
et cela donne :
///////////////////// METHODES PARTICULIERES DES ZONES ///////////////////////
// les methodes des zones
// Z0 gare base loisirs (pair/droite= z1 impair/gauche=butoir)
Zone* Z0::suivantePaire() { return z1; }
Zone* Z0::suivanteImpaire() { return NULL; }
// 1 VV centre (pair/droite=2, impair/gauche=0)
Zone* Z1::suivantePaire() { return z2; }
Zone* Z1::suivanteImpaire() { return z0; }
// 2 liaison VV-Hor (pair/droite=3, impair/gauche=1+aiguillePdevié=4)
Zone* Z2::suivantePaire() { return selonAiguille(a15,z3,NULL); }
Zone* Z2::suivanteImpaire() { return selonAiguille(a15,z1,selonAiguille(a16,NULL,z4)); }
// 3 gare centre (droite/pair=3=butoir, gauche/impair=2)
Zone* Z3::suivantePaire() { return NULL; }
Zone* Z3::suivanteImpaire() { return z2; }
// 4 GC Hor Ext (pair=6+aiguilleQdevié=2, impair=17)
Zone* Z4::suivantePaire() { return selonAiguille(a16,selonAiguille(a13,NULL,z7),selonAiguille(a15,NULL,z3)); }
Zone* Z4::suivanteImpaire() { return selonAiguille(a17,NULL,z16); }
// 5 GC Hor Int (pair=6, impair=17)
Zone* Z5::suivantePaire() { return selonAiguille(a13,z7,NULL); }
Zone* Z5::suivanteImpaire() { return selonAiguille(a17,z16,NULL); }
// 6 sortie GC Hor (pair=7, impair=5+aiguilleNdevié=4) - Normalement pas utilisé
Zone* Z6::suivantePaire() { return z7; }
Zone* Z6::suivanteImpaire() { return selonAiguille(a13,z5,selonAiguille(a16,z4,NULL)); }
etc..
Tests et SimulationsJ’ai réalisé un petit montage sur le Due, avec un écran graphique 2,4 pouces et 3 boutons poussoirs (+, - et OK).
+ et - permettent de se déplacer dans les lignes et OK execute une fonction (menu sélectionné ou action)
Le programme affiche une liste de menus:
- menus Aiguilles : je peux positionner chaque aiguille
- menu train : je peux définir le sens de déplacement
- menu Itinéraire : j’ai défini 7 points de départ. En appuyant sur OK, le programme demande la zone suivante successives aux objets en fonction des positions d’aiguilles (ici elles sont toutes droites, d’ou la série de « 1 » en bas de l’écran)
Ce petit bout de code fait tout (exemple pour le départ de la zone 5) :
zonedepart = 5;
Show("5 ");
zindex = 5;
for (int i=0; i<10; i++) {
zt = senstrain? listez[zindex]->suivantePaire() : listez[zindex]->suivanteImpaire();
if (zt == NULL) break;
zindex = zt->index;
tft.print(zindex);
tft.print(" ");
}
J’ai varié les positions d’aiguilles, le sens du train et à chaque fois, en vérifiant sur mon plan de réseau, les itinéraires sont tous bons !!!
CQFD
Un bon tuto suivra peut-être, prochainement.
Bien cordialement
Dominique