feuille d'appel 2023-2024: https://docs.google.com/spreadsheets/d/1kKCpiorHDFjv1qaqAmXEYFw1ch6o_PHPEUAOY5iQtk4/edit#gid=0 =====emplacements des fichiers étudiants==== en 2024, ils ont ~/adfscesi monté ils travaillent dans ~/ en local sur la machine, mais lié à leur compte. ils peuvent faire copie vers ~/adfscesi si jamais ils n'arrivent pas à se loguer, => ge2i mais faire le ménage sur la session et leur dire de sauver sur clef usb =====Fichiers à télécharger pour développer chez l'étudiant===== -> sous windows, ne marchera pas car j'ai utilisé les sockets linux pour la com avec le simulateur.. peut marcher uniquement pour le test unitaire sans communication avec le simultateur Télécharger QTcreator: https://www.qt.io/cs/c/?cta_guid=074ddad0-fdef-4e53-8aa8-5e8a876d6ab4&signature=AAH58kHfzUyp-YRHTGOQcji2bAkyHXCbiQ&pageId=12602948080&placement_guid=99d9dd4f-5681-48d2-b096-470725510d34&click=4b673b83-45c8-4f76-8565-3e53147ac801&hsutk=908fda3b2e6463692ece973aa2eeba3f&canon=https%3A%2F%2Fwww.qt.io%2Fdownload-open-source&portal_id=149513&redirect_url=APefjpE2-mzcsyLwibfbCsw2geX8WPkjo3SqRj5KpGbzDAYxQyQhnKPaUYflYOXA763Ez9nln_NctEBuN1N4VgmEKlRl77gINUGFMafl16Vq9BYNwMVqalERUU2S0P-mn-nXcI8g9Dau&__hstc=152220518.908fda3b2e6463692ece973aa2eeba3f.1679924698033.1679924698033.1679924698033.1&__hssc=152220518.1.1679924698033&__hsfp=1588722302&contentType=standard-page créer un compte A l'installation cocher: Design Tools Qt 6.4 pour le développement récupérer le squelette d'application sur: https://bvdp.inetdoc.net/files/cesi/tp2/mae_etudiant_vide.zip dézipper puis effacer manuellement les dossiers build.... et les fichiers .pro.user ouvrir le fichier .pro depuis qtcreator et cliquer sur "configurer le projet" dans le fichier sketch.cpp, commenter #include "lib_io_tp.h" dans le fichier tcp_client.pro, supprimer: lib_io_tp.cpp \ et lib_io_tp.h \ ouvrir le fichier .pro cliquer sur "configurer le projet" ajouter std:: devant les end pour le projet tcp_server_simulator, copier les *.png dans ..\Build... pour le projet mae_etudiant/tcp_client Probleme j'ai utilisé des fonctions unix pour le client TCP, ce n'est pas compatible windows https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server.zip https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server_simulator.zip TODO: mettre tous les fichiers telechargés et dossier dans ~/TP_InfoEmbarquee ====Corrections que j'ai fait sur le projet mae_etudiant_vide==== corriger lib_io_tp.cpp dans mae_etudiant pour virer de \ devant \o int setupES(char *ipAddressInit,char *portNumInit){ std::cout << "\ouverture socket vers : " << ipAddressInit << " : " < setName(strdup((std::string("Bertrand Vandeportaele").data()))); int r=setupES(strdup((std::string(ip).data())),strdup((std::string(port).data()))); if (r!=0){ printf("erreur ouverture socket, merci de lancer le simulateur ou d'allumer la carte téléopérée\n"); exit(-1); } setName(strdup((std::string(nom).data()))); printf("Elapsed time: %ld milliseconds\n", millis()); } ===Il faudra faire les mêmes corrections sur mes projets solutions sur rapid dans ~/Bureau/emul_arduino/=== Idée: générer fichier vcd pour le test unitaire et regarder avec gtkwave???? =====TP 2 Informatique Embarquée Avancée CESI===== =====Informations avant de commencer!===== {{https://bvdp.inetdoc.net/files/iut/tp_pic/warning.jpeg}} Pour faire le TP, vous devrez bien lire le sujet, ne pas sauter de parties, ne pas inventer de prototypes de fonctions mais bien respecter ce qui est demandé, car les fonctions que vous écrirez devront pouvoir être substituées à d'autres fonctions ayant les mêmes prototypes. Les marges de manœuvre dont vous disposez sont au niveau de l'implémentation de ces fonctions, mais les prototypes font partie du cahier des charges et ne sont pas négociables! Le TP se déroulera sur plusieurs séances, il est de votre responsabilité de conserver les fichiers que vous aurez produits; pour cela, vous pourrez vous envoyer par mail ou via clef USB une archive zip de votre dossier de projet à chaque fin de séance pour éviter toute perte. De plus cette archive devra être fournie à l'enseignant pour évaluation en fin de projet. =====Description du dispositif à piloter et du système de commande===== ====Dispositif à piloter==== Vous allez devoir réaliser un système de commande d'un dispositif de tri industriel doté de capteurs et d'actionneurs. Ce dispositif est visible sur la figure suivante: {{https://bvdp.inetdoc.net/files/cesi/tp2/station_rempli.png}} Les informations fournies par les capteurs sont accessibles pour votre système de commande sur différents bits d'un port d'entrée 8 bits tel qu'indiqué sur la figure, les bits étant positionnés à 0 lorsque le capteur s'active. Les commandes des actionneurs sont réalisées par votre système de commande sur différents bits d'un port de sortie 8 bits tel qu'indiqué sur la figure, les bits étant positionnés à 1 pour activer un actionneur. ====Système de commande==== L'interaction entre votre système de commande et la maquette à piloter se résume donc à un port d'entrée et un port de sortie, comme lors du TD1: [[cesitd1]]. De plus le système de commande intègre un écran LCD à deux lignes qui vous permettra d'afficher vos noms et des messages pendant l'exécution du programme. Dans le TP, nous réaliserons le système de commande en plusieurs étapes: - Vous écrirez le système de commande sur PC et simulerez les entrées/sorties à l'aide d'une application graphique dotée de boutons et d'afficheurs (mode simulé). Vous pourrez également utiliser une application simulant le processus industriel pour tester votre système de commande. - Vous réaliserez des programmes de tests sur PC pour vérifier (et dans une certaine mesure prouver) le bon fonctionnement de votre système de commande (mode test unitaire). - Vous réaliserez depuis le PC la commande à distance des entrées/sorties physiques d'un microcontrôleur vers le dispositif réel (mode télé-opéré). - Vous réaliserez finalement la commande directement depuis le microcontrôleur simulé avec Wokwi (mode embarqué simulé). - Vous réaliserez finalement la commande directement depuis le microcontrôleur raccordé au dispositif à piloter (mode embarqué). =====Analyse pour le tri des pièces par type===== ===Détermination du type de pièce en fonction de l'activation des capteurs=== Les trois capteurs permettant de détecter les pièces sont positionnés en différents lieux sur le tapis roulant, et afin de déterminer si une pièce est Noire, Rouge ou Metallique, il est nécessaire de scruter l'activation successive des différents capteurs. Le tableau suivant récapitule la séquence d'activation des capteurs pour les différentes pièces: Type de pièce, capteur NON_NOIR, capteur METAL, capteur PRESENT Noire , , , X Rouge , X, , X Métal , X, X , X ====Machine à états==== Nous proposons d'utiliser une machine à états pour trier les pièces, afin de piloter les différents actionneurs du dispositif en fonction des informations fournies par les capteurs et du comportement souhaité: * La station de tri doit amener dans la glissière 2 les pièces noires. * La station de tri doit amener dans la glissière 1 les pièces métalliques. * La station de tri doit amener dans la glissière 0 les pièces rouges. * Le tapis roulant doit s’arrêter lorsque la glissière est pleine. Il est vivement recommandé de raisonner sur l'activation des capteurs en utilisant des variables qui seront affectées au complément des valeurs lues sur les entrées correspondantes car les capteurs fournissent des signaux actifs à 0. Voir avec l'enseignant une machine à état (sans les actions) permettant de préparer ce comportement. Vous devrez par la suite réaliser vous même les actions. {{https://bvdp.inetdoc.net/files/cesi/tp2/cesifesto1sansactions.gif}} /* Copyright (c) 2022, Bertrand Vandeportaele, LAAS/CNRS All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of California, Berkeley nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 0; /* 1: marche=Inter0:sens:A8; 2: marche=Inter0; 3: marche=Inter0:sens:A9; 4: marche=Inter0:A9; 5: marche=Inter0:sens; 6: marche=Inter0:A8; */ //on raisonne avec les activations de capteurs, pas les états (car actif à niveau bas) 0 -> 1 ?NON_NOIR AND NOT PRESENT; 1 -> 2 ?METAL AND NOT PRESENT; 2 -> 3 ?PRESENT; 3 -> 4 ?NOT PLEIN; 4 -> 5 ?PLEIN; 5 -> 0 ?NOT PLEIN; 1 -> 6 ?PRESENT; 6 -> 7 ?NOT PLEIN; 7 -> 8 ?PLEIN; 8 -> 0 ?NOT PLEIN; 0 -> 9 ?PRESENT; 9 ->10 ?NOT PLEIN; 10->11 ?PLEIN; 11-> 0 ?NOT PLEIN; //Actions toujours vraies %I,stoppeur_retracte; 0:MOTEUR=NOT PLEIN; 1:MOTEUR=NOT PLEIN; 2:MOTEUR=NOT PLEIN; 3:SWITCH2; 4:MOTEUR=NOT PLEIN:SWITCH2; 5; 6:SWITCH1; 7:MOTEUR=NOT PLEIN:SWITCH1; 8; 9; 10:MOTEUR=NOT PLEIN; 11; #pragma_dot_global_directive{ rankdir=TB; ranksep=0.1; nodesep=0.2; }#pragma //to testbench this file, just type ./run_tb.sh train 10000us in example/ghdl directory #pragma_vhdl_testbench{ --------------------------------------- --------------------------------------- }#pragma {{https://bvdp.inetdoc.net/files/cesi/tp2/cesifesto1avecactions.gif}} =====Étapes pour démarrer le projet==== VIRE, date de l'époque ou les étudiants travaillaient sur session locale GEII ====Ménage sur la session utilisateur local==== A faire uniquement à la première séance rm -rf ~/*.zip* ~/tcp_server_simulator ~/tcp_server ~/mae_etudiant_vide ====Récupération du simulateur d'entrées/sorties==== Copier coller dans un terminal les commandes suivantes A LA PREMIERE SEANCE UNIQUEMENT, afin de récupérer le projet et de le compiler: cd ~ wget https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server.zip unzip tcp_server.zip rm tcp_server.zip cd tcp_server rm -rf build* cd tcp_server qmake make clean make ./tcp_server & Par la suite, pour lancer le simulateur, il vous suffira de saisir dans un terminal: ~/tcp_server/tcp_server/tcp_server & Vous devez voir la fenêtre suivante s'ouvrir, qui vous permet de piloter l'état des entrées et de visualiser l'état des sorties. Elle permet également l'affichage de votre nom ainsi que de différents messages pendant l’exécution de votre programme. {{https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server.png}} ====Récupération du simulateur d'entrées/sorties et de la maquette==== Copier coller dans un terminal les commandes suivantes A LA PREMIERE SEANCE UNIQUEMENT, afin de récupérer le projet et de le compiler: cd ~ wget https://bvdp.inetdoc.net/files/cesi/tp2/tcp_server_simulator.zip unzip tcp_server_simulator.zip rm tcp_server_simulator.zip cd tcp_server_simulator rm -rf build* .git tcp_server_simulator.pro.user station_rempli.png station_vide2.png station_vide.png 'switch*$.png' qmake make clean make ./tcp_server_simulator & Par la suite, pour lancer le simulateur, il vous suffira de saisir dans un terminal: cd ~/tcp_server_simulator/ && ./tcp_server_simulator & ====Récupération du projet de départ==== Copier coller dans un terminal les commandes suivantes A LA PREMIERE SEANCE UNIQUEMENT, afin de récupérer le projet de départ et d'initialiser l'outils de gestion de versions: echo commence cd ~ wget https://bvdp.inetdoc.net/files/cesi/tp2/mae_etudiant_vide.zip unzip mae_etudiant_vide.zip rm mae_etudiant_vide.zip mv mae_etudiant_vide mae_etudiant cd mae_etudiant/tcp_client git init git add * git commit -m'Version initiale fournie par B.Vandeportaele' qtcreator tcp_client.pro & gitk & echo fini A l'ouverture de Qtcreator, cliquer sur le bouton "Configurer le projet", le choix de kit proposé étant normalement correct. ====Structure du projet==== Le projet que vous avez récupéré comporte plusieurs fichiers permettant de générer un exécutable pour le PC: - Arduino.cpp et Arduino.h forment une librairie permettant d'émuler la fonction de gestion du temps **millis()** de l'Arduino sur le PC. - lib_io_tp.cpp et lib_io_tp.h forment une librairie permettant de piloter des ports d'entrées/sorties 8 bits ainsi qu'un écran à cristaux liquide via le réseau à l'aide de socket TCP. Cette librairie communique soit avec une vrai carte Arduino soit avec un programme permettant de l'émuler. - sketch.cpp et sketch.h forment votre librairie contenant les fonctions **setup()** et **loop()** qui seront par la suite portées sur l'Arduino. Le projet fourni contient un code d'exemple qui illustre l'utilisation des fonctions des librairies Arduino et lib_io_tp et qui vous servira de base de départ pour votre propre programme. - main.cpp contient le programme principal. - tcp_client.pro est un fichier décrivant le projet QT, les règles de compilation, les librairies à utiliser etc... ====Présentation de la librairie pour les Entrées/Sorties==== Voici la description des fonctions disponibles dans la libraire pour piloter les E/S: /*! \file lib_io_tp.h \brief Librairie E/S via TCP pour le CESI. \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #ifndef LIB_IO_TP_H #define LIB_IO_TP_H // Bertrand Vandeportaele 2022 // inspiré d'un exemple de client TCP simple sans QT: // https://riptutorial.com/cplusplus/example/24000/hello-tcp-client #include "Arduino.h" #include #include #include #include #include #include #include #include /*! * \brief setupES Configure les entrées sorties émulées ou télé-opérées vers l'hôte ipAddressInit via le port TCP portNumInit * \param ipAddressInit * \param portNumInit * \return */ int setupES(char *ipAddressInit,char *portNumInit); /*! * \brief closeES Libère les ressources de communications utilisées par la librairie */ void closeES(); /*! * \brief readPort Lit l'état du port d'entrée 8 bits * \return l'état du port d'entrée 8 bits */ unsigned char readPort(void); /*! * \brief writePort Pilote l'état du port de sortie 8 bits * \param value l'état du port de sortie 8 bits */ void writePort(unsigned char value); /*! /*! * \brief setName Règle votre nom à afficher sur l'écran LCD ou dans la zone de texte de l'émulateur /*! * \param value la chaine de caractères contenant votre nom /*! */ void setName(char *value); /*! * \brief setMsg Règle un message à afficher sur l'écran LCD ou dans la zone de texte de l'émulateur * \param value la chaine de caractères contenant le message */ void setMsg(char *value); // formats de requetes TCP: // g \n pour lecture port // s val\n pour ecriture port // n nom\n pour affichage nom // m message\n pour affichage message #endif // LIB_IO_TP_H Pour l'émulation des E/S sur votre PC en local, vous utilisez l'IP de la boucle locale: 127.0.0.1 et le numéro de port: 4242. Pour la télé-opération des E/S sur la carte microcontrôleur, vous utilisez l'IP: 172.16.6.60 et le numéro de port: 4242. L'adaptateur Ethernet du microcontrôleur est connecté sur une prise VLAN bleue. ====Notice d'utilisation de l'outils QTCreator==== Une fois le projet ouvert, l'utilisateur peut choisir entre plusieurs mode d'affichages, notamment "Editer" et "Debogage" à l'aide des boutons sur la gauche de la fenêtre. La fenêtre Projets fait apparaître les fichiers du (des) projet(s) ouvert(s), triés selon leur type. Sur la droite, la fenêtre affiche le contenu d'un fichier sélectionné. **CTRL+Click souris gauche** sur un mot du programme permet de se déplacer à la déclaration d'une variable, d'un objet, d'une fonction, d'un type ou autre. Cela sera très utile pour connaître par exemple les méthodes utilisables sur un objet d'une certaine classe. **CTRL+B** permet de compiler l'application, la fenêtre Sortie de compilation permet alors d'observer les éventuelles erreurs, sur lesquelles vous pourrez cliquer pour aller à la ligne correspondante dans le code. **CTRL+R** permet d’exécuter le programme. Le programme devra être fermé en cliquant sur le bouton croix de la fenêtre avant de le recompiler ou de l’exécuter à nouveau. **F5** permet d'exécuter le programme en mode DEBUG. L'utilisateur passe alors en mode Debug, ce qui ajoute à l'affichage une zone à droite dans laquelle l'utilisateur pourra observer les variables et leurs valeurs. L'utilisateur pourra placer ou retirer des points d'arrêt en cliquant à gauche du numéro de ligne d'un fichier. Il pourra exécuter en pas à pas sans rentrer dans les fonctions à l'aide de **F10** ou bien en entrant dans les fonctions à l'aide de **F11**. Il pourra ajouter une variable particulière à la liste des variables affichées en Debug en selectionant le nom de la variable dans le fichier programme et en cliquant droit dessus puis clic gauche sur **ajouter un évaluateur d'expression**. ====Utilisation de l'outil de gestion de version depuis QT==== Pour créer une version, au moins à chaque validation, vous devrez cliquer sur Outils->Git->Dépot local->Commit, cliquer sur Fichiers->Select all, et saisir un texte descriptif dans le champ Description. Ensuite cliquer sur Soumettre. Pour visualiser les différentes versions, vous devrez cliquer sur Outils->Git->Outils Git->gitk ====Test du projet de départ==== Compiler et exécuter le projet de départ, alors que l'application tcp_server est en cours d'exécution. Jouer sur les entrées et observer le comportement de l'application. Relier ce comportement au code du projet de départ pour en comprendre le fonctionnement. ====Implémentation de la machine à états==== Implémenter la machine à états dans le fichier sketch.cpp comme cela a été montré en [[cesitd3]] (s'identifier en login:au , mot de passe: au pour voir les solutions du td3). Modifier le code de la fonction **loop()** pour que votre machine soit reliée aux entrées/sorties et soit cadencée à 200Hz. Faire en sorte d'afficher votre nom et un message indiquant l'état actif de la machine à état à chaque évolution. Tester complètement le bon fonctionnement de votre programme en jouant sur les entrées et en déduire des séquences de tests. {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-1.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. ====Réalisation de la fonction de test unitaire de la machine à états==== A partir des séquences de tests déterminées à l'exercice précédent, écrire et exécuter un programme de test complet **void programmeDeTest1()** faisant apparaître le maintien dans chaque état et toutes les transitions comme montré en [[cesitd3]]. Pour cela, vous devrez adapter le code pour que l'affichage se fasse sur la console du PC au lieu de celle de l'arduino. Vous utiliserez donc la fonction **debugMessage** suivante: //////////////////////////////////////////////////////////////////// //! fonction d'affichage d'un message de debug bien pratique, //! qui affiche un message texte, le nom du fichier et le numéro de la ligne //! depuis où la fonction a été appelée void debugMessage(const char * chaineMsg,const char * chaineFile,const unsigned int line){ printf("DEBUG %s : l %d : %s\n",chaineFile,line,chaineMsg); flush(std::cout); } et vous remplacerez les affichages réalisés avec Serial.print par des appels à la fonction **printf**. Vous pourrez utiliser ce squelette de programme de test et le compléter. Cette fonction devra être appelée par la fonction **setup()**: void programmeDeTest1(){ //! Le composant à tester CStateMachine mae; printf("\nTest lancé le "); printf("%s",__DATE__ ); printf(" à "); printf("%s",__TIME__ ); printf("\nFonction de test: "); printf(__func__); //boucle pour gérer les différents cas à tester int ntest=1; printf("\ndébut du test numéro: "); printf("%d\n",ntest); mae.reset(); mae.setEntree(0xF); mae.clock(); //ici on teste la mae sans considération de timing, donc clock() n'est pas conditionné à un timer mae.clock(); //Compléter le test ici: if (mae.getEtat()!=......) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //fin du test debugMessage("\nFin du test\n", __FILE__, __LINE__); exit(0); //commenter cette ligne pour ne pas quitter le programme après la fin du test } ////////////////////////////////////////////////////// {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-2.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. ====Test en mode télé-opéré==== Adapter le programme pour le tester en mode télé-opéré sur la maquette réelle. Vous veillerez à indiquer au tableau le nom du binôme utilisant la maquette à un instant donné pour éviter qu'un autre binôme n'interfère. {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-3.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. ====Test en mode embarqué (tout simulé)===== Insérer le code de vos fonctions **setup()** et **loop()** dans le projet du TD1: [[cesitd1]] et tester avec wokwi le bon fonctionnement en embarqué dans le simulateur. Vous devrez dans setup(), après avoir appelé setupES(), appeler 1 fois readPort() et writePort(0); Vous aurez besoin d'ajouter à la librairie du TD1 les fonctions suivantes: /////////////////////////////////////////////////////// void setName(char *value) { Serial.println(value); } /////////////////////////////////////////////////////// void setMsg(char *value) { Serial.println(value); } /////////////////////////////////////////////////////// {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-4.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version (sous Wokwi). ====Test en mode embarqué (E/S simulé)===== Programmer une vraie carte Arduino dotée d'entrées/sorties telle que visible sur la carte [[tdcom2]] en utilisant la librairie d'entrées/sortie suivante et tester: /*! \file lib_io_tp.h \brief Premier TD pour le CESI. \author Bertrand Vandeportaele IUT GEII \date 28/10/2021 */ #include void SetupES(void); unsigned char readPort(void); void writePort(unsigned char value); void setName(char *value); void setMsg(char *value); /*! \file lib_io_tp.cpp \brief Premier TD pour le CESI. \author Bertrand Vandeportaele IUT GEII \date 28/10/2021 */ #include "lib_io_tp.h" bool SIMULATION=false; //si cette variable est true, alors la librairie utilise les composants registres //à décalage en simulation sur Wokwi, sinon elle utilise les composants PCF8574 de la carte de TP //Pour les composants I2C: #include #define SLAVE_ADDR_8574_A (0x38+6) #define SLAVE_ADDR_8574_B (0x38+7) //Pour les composants en simulation: //Librairie pour registres à décalage sur Wokwi.com /*mix de https://wokwi.com/arduino/projects/313005664351814210 et de https://wokwi.com/arduino/projects/301188813482361352 */ // Pin definitions: const int datapin_in = 9; /* Q7 */ const int clockpin_in = 8; /* CP */ const int latchpin_in = 4; /* PL */ const int datapin_out = 5; const int clockpin_out = 6; const int latchpin_out = 7; /////////////////////////////////////////////////////// /*! * \brief Fonction d'initialisation des ressources matérielles pour accéder aux ports d'entrée/sortie */ void SetupES(void){ Wire.begin(); delay(100); //teste si un composant 8574 est présent sur la carte for (byte addr=0x38;addr<=0x3f;addr++){ Wire.requestFrom(addr, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique if (Wire.available()==1) { Wire.read(); SIMULATION=false; //Utilisation des composants I2C plutot que des registres à décalage //Serial.print("premier composant i2c trouvé a:");Serial.println(addr,HEX); break; } } if (SIMULATION==false){ delay(100); Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);Wire.write((byte)0xff);Wire.endTransmission();//configure le composant B en entrée }else{ pinMode(datapin_in, INPUT); pinMode(clockpin_in, OUTPUT); pinMode(latchpin_in, OUTPUT); // Set the three SPI pins to be outputs: pinMode(datapin_out, OUTPUT); pinMode(clockpin_out, OUTPUT); pinMode(latchpin_out, OUTPUT); } } /////////////////////////////////////////////////////// /*! * \brief Fonction de lecture du port d'entrée * @return valeur 8 bits lue sur le port */ unsigned char readPort(void){ if (SIMULATION==false){ Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique if (Wire.available()==1) //si l'octet est disponible return Wire.read(); // lire l'octet else return 0; }else{ unsigned char val=0; // Step 1: Sample digitalWrite(latchpin_in, LOW); digitalWrite(latchpin_in, HIGH); for (int i = 0; i < 8; i++) { int bit = digitalRead(datapin_in); val=(val<<1)|bit; digitalWrite(clockpin_in, HIGH); // Shift out the next bit digitalWrite(clockpin_in, LOW); } return val; } } /////////////////////////////////////////////////////// /*! * \brief Fonction d'écriture vers le port de sortie * @param value valeur 8 bits à écrire sur le port */ void writePort(unsigned char value){ //cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur if (SIMULATION==false){ Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique Wire.write(~(byte)value); //envoie la donnée complémentée car les LEDs s'allument à l'état 0 Wire.endTransmission(); }else{ shiftOut(datapin_out, clockpin_out, MSBFIRST, value); //Send "data" to the shift register //Toggle the latchpin_out to make "data" appear at the outputs digitalWrite(latchpin_out, HIGH); digitalWrite(latchpin_out, LOW); } } /////////////////////////////////////////////////////// void setName(char *value) { Serial.println(value); } /////////////////////////////////////////////////////// void setMsg(char *value) { Serial.println(value); } /////////////////////////////////////////////////////// {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-5.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. ====Test en mode embarqué complet===== Installer la librairie LiquidCrystal_I2C dans Arduino. Pour cela, cliquer dans l'IDE arduino sur Croquis->Inclure une Bibliothèque->Gérer les Bibliothèques et copier coller "LiquidCrystal_I2C" dans le champ "Filtrer votre recherche". Selectionner dans la liste "LiquidCrystal_I2C by Frank Brabander" en version 1.1.2 et cliquer sur Installer. Avec l'enseignant, programmer LA carte Arduino raccordée à la station de tri en utilisant la librairie d'entrées/sortie suivante et tester: /*! \file lib_io_tp.h \brief Librairie IO+LCD pour FESTO \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #include #include void SetupES(void); unsigned char readPort(void); void writePort(unsigned char value); void setName(char *value); void setMsg(char *value); /*! \file lib_io_tp.cpp \brief Librairie IO+LCD pour FESTO \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #include "lib_io_tp.h" //pour utiliser carte d'interface et gérer inversion des quartets + E et S inversées A/B par rapports aux inter et led.. #define FESTO #include #define SLAVE_ADDR_8574_A (0x38+6) #define SLAVE_ADDR_8574_B (0x38+7) LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display //doc sur https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/LiquidCrystal_I2C.h #ifdef FESTO ////////////////////////////////////////// char swapNibles(char in) { //le port de sortie est cablé en inversant les 4 bits MSB avec les LSB return (( (in & 0x0f) << 4) | ((in >> 4) & 0x0f)); } ////////////////////////////////////////// #endif /////////////////////////////////////////////////////// /*! \brief Fonction d'initialisation des ressources matérielles pour accéder aux ports d'entrée/sortie */ void SetupES(void) { Wire.begin(); delay(100); #ifdef FESTO Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant A en entrée Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant B en sortie #else Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant A en sortie Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée #endif // Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée lcd.init(); // initialize the lcd lcd.backlight(); lcd.print("Nom:"); lcd.setCursor(0, 1); lcd.print("Msg:"); } /////////////////////////////////////////////////////// /*! \brief Fonction de lecture du port d'entrée @return valeur 8 bits lue sur le port */ unsigned char readPort(void) { #ifdef FESTO Wire.requestFrom((byte)SLAVE_ADDR_8574_A, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique #else Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique #endif if (Wire.available() == 1) //si l'octet est disponible return Wire.read(); // lire l'octet else return 0; } /////////////////////////////////////////////////////// /*! \brief Fonction d'écriture vers le port de sortie @param value valeur 8 bits à écrire sur le port */ void writePort(unsigned char value) { //cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur #ifdef FESTO Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);//démarre la transmission avec l'adresse du pérpiphérique Wire.write((byte)swapNibles(value)); //envoie la donnée non complémentée #else Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique Wire.write(~(byte)value); //envoie la donnée complémentée car les LEDs s'allument à l'état 0 #endif Wire.endTransmission(); } /////////////////////////////////////////////////////// void printlcd(char *value, int nligne) { lcd.setCursor(4, nligne); int i; for (i = 0; i < 12; i++) { if ((value[i] == '\0') || (value[i] == '\n')) break; else lcd.write( value[i]); } //si i<12; on efface avec des ' ' while (i < 12) { lcd.write(' '); i++; } } /////////////////////////////////////////////////////// void setName(char *value) { printlcd(value, 0); } /////////////////////////////////////////////////////// void setMsg(char *value) { printlcd(value, 1); } {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-6.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. ====Evolution de la MAE pour réaliser des séquences de pièces===== Proposer une adaptation de la machine à états permettant de réaliser: -dans la glissière 2, une séquence de pièces rouge/noire/rouge. -dans la glissière 1, deux métalliques et une noire, dans n'importe quel ordre. -dans la glissière 0, le stockage des pièces non utilisables. Réaliser la démarche de test comme précédemment. {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-7.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. ====Parallélisme de tâches===== Pour illustrer le parallélisme de tâches, vous allez scinder la machine à états en 2 machines à états séparées afin de permettre au système de gérer l'arrivée d'une pièce en amont du tapis alors qu'une pièce est en cours de transit vers une glissière: - La première permet de déterminer le type de pièce, et bloque la pièce en attente grâce au stoppeur. - La deuxième permet d'acheminer une pièce du stoppeur jusqu'à la bonne glissière. Les deux machines a états doivent communiquer: La première doit informer la deuxième du type de pièce détectée et attendre que la deuxième lui demande d'envoyer la pièce. Proposer un dessin des deux machines à états et après validation par l'enseignant, réaliser la démarche de test comme précédemment. {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}}{{https://bvdp.inetdoc.net/files/imageschiffres/chiffre-8.jpg?40%}}} Appeler un enseignant pour valider votre travail et sauver une version. =====Annexes===== =====Projet solution===== cd ~ wget https://bvdp.inetdoc.net/files/cesi/tp2/mae_etudiant.zip unzip mae_etudiant.zip rm mae_etudiant.zip cd mae_etudiant/tcp_client qmake make clean qtcreator tcp_client.pro & =====Application Arduino TCPServerIO===== /*! \file TCPServerIO.ino \brief Distant Input/Output via TCP for Arduino \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ /* Inspired from Web Server demo application created 18 Dec 2009 by David A. Mellis modified 9 Apr 2012 by Tom Igoe modified 02 Sept 2015 by Arturo Guadalupi */ #include "lib_io_tp.h" //activer ce flag pour débugguer les requetes/réponses #define DEBUG_TCP_REQ //voir la doc: file:///home/bvandepo/T%C3%A9l%C3%A9chargements/arduino-1.8.13/reference/www.arduino.cc/en/Reference/Ethernet.html #include #include // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x05 }; //maison: IPAddress ip(192, 168, 1, 177); //IUT gomette bleue: IPAddress ip(172,16,6,60); // Initialize the Ethernet server library // with the IP address and port you want to use EthernetServer server(4242); void setup() { // You can use Ethernet.init(pin) to configure the CS pin //Ethernet.init(10); // Most Arduino shields //Ethernet.init(5); // MKR ETH shield //Ethernet.init(0); // Teensy 2.0 //Ethernet.init(20); // Teensy++ 2.0 //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet SetupES(); // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("TCPServerIO Bertrand Vandeportaele 2022"); // start the Ethernet connection and the server: Ethernet.begin(mac, ip); // Check for Ethernet hardware present if (Ethernet.hardwareStatus() == EthernetNoHardware) { Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); while (true) { delay(1); // do nothing, no point running without Ethernet hardware } } if (Ethernet.linkStatus() == LinkOFF) { Serial.println("Ethernet cable is not connected."); } // start the server server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP()); } void loop() { static char chaine[100]; static int nb_received = 0; // listen for incoming clients EthernetClient client = server.available(); if (client) { Serial.println("new client"); // an http request ends with a blank line boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { unsigned char entree; char c = client.read(); #ifdef DEBUG_TCP_REQ Serial.write(c); #endif chaine[nb_received] = c; //TODO : avoid leaks nb_received++; if (c == '\n') { unsigned char v; chaine[nb_received] = '\0'; switch ( chaine[0]) { case 's': v = atoi(chaine + 2); #ifdef DEBUG_TCP_REQ Serial.print(" -> requete s "); Serial.println(v); #endif writePort(v); entree = v; break; case 'g': v = atoi(chaine + 2); #ifdef DEBUG_TCP_REQ Serial.print(" -> requete g "); Serial.println(v); #endif entree = readPort(); break; case 'm': #ifdef DEBUG_TCP_REQ Serial.print(" -> requete m "); Serial.println(chaine + 2); #endif setMsg(chaine + 2); entree = 0; break; case 'n': #ifdef DEBUG_TCP_REQ Serial.print(" -> requete n "); Serial.println(chaine + 2); #endif setName(chaine + 2); entree = 0; break; } //envoi reponse à la requete: //itoa(entree, chaine, 10); sprintf(chaine, "%03d\n", entree); client.print(chaine); #ifdef DEBUG_TCP_REQ Serial.print(" -> réponse "); Serial.println(chaine); #endif nb_received = 0; //reinit pour la requete suivante } } } delay(1); // close the connection: client.stop(); Serial.println("client disconnected"); } } /*! \file lib_io_tp.cpp \brief Librairie IO+LCD pour FESTO \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #include "lib_io_tp.h" //pour utiliser carte d'interface et gérer inversion des quartets + E et S inversées A/B par rapports aux inter et led.. #define FESTO #include #define SLAVE_ADDR_8574_A (0x38+6) #define SLAVE_ADDR_8574_B (0x38+7) LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display //doc sur https://github.com/johnrickman/LiquidCrystal_I2C/blob/master/LiquidCrystal_I2C.h #ifdef FESTO ////////////////////////////////////////// char swapNibles(char in) { //le port de sortie est cablé en inversant les 4 bits MSB avec les LSB return (( (in & 0x0f) << 4) | ((in >> 4) & 0x0f)); } ////////////////////////////////////////// #endif /////////////////////////////////////////////////////// /*! \brief Fonction d'initialisation des ressources matérielles pour accéder aux ports d'entrée/sortie */ void SetupES(void) { Wire.begin(); delay(100); #ifdef FESTO Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant A en entrée Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant B en sortie #else Wire.beginTransmission((byte)SLAVE_ADDR_8574_A); Wire.write((byte)0x00); Wire.endTransmission(); //configure le composant A en sortie Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée #endif // Wire.beginTransmission((byte)SLAVE_ADDR_8574_B); Wire.write((byte)0xff); Wire.endTransmission(); //configure le composant B en entrée lcd.init(); // initialize the lcd lcd.backlight(); lcd.print("Nom:"); lcd.setCursor(0, 1); lcd.print("Msg:"); } /////////////////////////////////////////////////////// /*! \brief Fonction de lecture du port d'entrée @return valeur 8 bits lue sur le port */ unsigned char readPort(void) { #ifdef FESTO Wire.requestFrom((byte)SLAVE_ADDR_8574_A, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique #else Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique #endif if (Wire.available() == 1) //si l'octet est disponible return Wire.read(); // lire l'octet else return 0; } /////////////////////////////////////////////////////// /*! \brief Fonction d'écriture vers le port de sortie @param value valeur 8 bits à écrire sur le port */ void writePort(unsigned char value) { //cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur #ifdef FESTO Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);//démarre la transmission avec l'adresse du pérpiphérique Wire.write((byte)swapNibles(value)); //envoie la donnée non complémentée #else Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique Wire.write(~(byte)value); //envoie la donnée complémentée car les LEDs s'allument à l'état 0 #endif Wire.endTransmission(); } /////////////////////////////////////////////////////// void printlcd(char *value, int nligne) { lcd.setCursor(4, nligne); int i; for (i = 0; i < 12; i++) { if ((value[i] == '\0') || (value[i] == '\n')) break; else lcd.write( value[i]); } //si i<12; on efface avec des ' ' while (i < 12) { lcd.write(' '); i++; } } /////////////////////////////////////////////////////// void setName(char *value) { printlcd(value, 0); } /////////////////////////////////////////////////////// void setMsg(char *value) { printlcd(value, 1); } /*! \file lib_io_tp.h \brief Librairie IO+LCD pour FESTO \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #include #include void SetupES(void); unsigned char readPort(void); void writePort(unsigned char value); void setName(char *value); void setMsg(char *value); void loop(){ unsigned int periodiciteTache1=1000; static unsigned long timerTache1 = millis(); if (millis() - timerTache1 >= periodiciteTache1) { timerTache1 += periodiciteTache1; static char c=0; std::cin >>c; std::cin.get(); std::cout << "c vaut:" << c; if ((c>='0') && (c<='9')){ c=c-'0'; writePort(c); }else if ((c>='A') && (c<='F')){ c=c-'A'+10; writePort(c); }else if ((c>='a') && (c<='f')){ c=c-'f'+10; writePort(c); } //c=(c+1)%16; //writePort(c); //=getkey(); //readPort(); } /*unsigned int periodiciteTache2=1000; static unsigned long timerTache2 = millis(); if (millis() - timerTache2 >= periodiciteTache2) { timerTache2 += periodiciteTache2; static unsigned int cpt=0; cpt++; char chaine[100]; sprintf(chaine,"cpt=%d",cpt); printf(chaine); setMsg(chaine); }*/ } Programme de test simple pour verifier les E/S depuis teleopération: /*! \file sketch.cpp \brief Emulation sketch Arduino pour le CESI. \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #include "sketch.h" #include "lib_io_tp.h" ////////////////////////////////////////////////////// void setup(){ init_millis(); //boucle locale pour simu //int r=setupES("127.0.0.1","4242"); //arduino iut gomette bleue int r=setupES("172.16.6.60","4242"); setName("Bertrand Vandeportaele"); if (r!=0) printf("erreur ouverture socket\n"); printf("Elapsed time: %ld milliseconds\n", millis()); } ////////////////////////////////////////////////////// void loop(){ unsigned int periodiciteTache1=2000; static unsigned long timerTache1 = millis(); static unsigned char cptTache1=0; if (millis() - timerTache1 >= periodiciteTache1) { timerTache1 += periodiciteTache1; // writePort(readPort()); writePort(1<= periodiciteTache2) { timerTache2 += periodiciteTache2; static unsigned int cpt=0; cpt++; char chaine[100]; unsigned char E=readPort(); for (int i=0;i<8;i++) chaine[7-i]=((E>>i)&1)+'0'; chaine[8]=0; //sprintf(chaine,"cpt=%d,E=%02X",cpt, readPort()); printf(chaine); setMsg(chaine); } } Solution pour téléopération (à tester, récupérée sur compte IUT/bvdp/mae_etudiant/tcp_client): #include "sketch.h" #include "lib_io_tp.h" //////////////////////////////////////////////////////////////////// class CStateMachine //déclaration de la classe { //! membres accessibles depuis l'extérieur de la classe, il s'agit de l'interface d'interaction de la classe public: //! Constructeur CStateMachine(); //! méthode pour redémarrer la machine à état void reset(); //! méthode pour cadencer la machine à état (faire 1 coup d'horloge) void clock(); //! méthode manipulateur pour fournir les entrées void setEntree(unsigned char entreeval) { entree=entreeval;} //! méthode manipulateur pour fournir les entrées individuellement void setEntreeBit(unsigned char nbit,unsigned char entreeval) { entree= (entree&~(1<>nbit)&1;} //! méthode accesseur pour accéder à l'état courant unsigned char getEtat() { return etat;} //! membres privés pour réaliser l'encapsulation: ces attributs sont inacessibles directement depuis l'extérieur de la classe private: //! numéro de l'état actif unsigned char etat; //! valeur des entrées unsigned char entree; //! valeur des sorties unsigned char sortie; }; //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //Implémentation de la méthode constructeur CStateMachine::CStateMachine(){ // à compléter si besoin, allocation etc... reset(); } //////////////////////////////////////////////////////////////////// //Implémentation de la méthode reset, tout ce qui est fait pour (re)démarrer la machine à états void CStateMachine::reset(){ etat=0; sortie=0; //mettre des valeurs initiales correctes } //////////////////////////////////////////////////////////////////// //Implémentation de la méthode clock void CStateMachine::clock(){ //variables intérmédiaires pour les entrées unsigned char present =( (entree>>0)&1 ) ^1; unsigned char metal =( (entree>>1)&1 ) ^1; unsigned char non_noir =( (entree>>2)&1 ) ^1; unsigned char plein =( (entree>>3)&1 ) ^1; //AMZI unsigned char moteur=0; unsigned char switch1=0; unsigned char switch2=0; unsigned char stoppeur_retracte=1; //toujours rétracté //variables intérmédiaires pour les sorties //codage des sorties //moteur est une AMZI //if ( (etat==0) || (etat==1) || (etat==2) || (etat==3) || (etat==4) || (etat==6) || (etat==7) || (etat==9) || (etat==10) ) if ( ( (etat==0) || (etat==1) || (etat==2) || (etat==4) || (etat==7) || (etat==10) ) && (plein==0)) moteur=1; else moteur=0; if ( (etat==6) || (etat==7) ) switch1=1; else switch1=0; if ( (etat==3) || (etat==4) ) switch2=1; else switch2=0; /*unsigned char sortie0; if (etat==3) sortie0=entree1; else sortie0=0; //Sortie1 est une AMZI unsigned char sortie1; if (etat==1) sortie1=entree1; else if ((etat==3)&& (entree0==0)) sortie1=entree2; else sortie1=0; //Sortie2 est une AMZE unsigned char sortie2=(sortie>>2)&1; //récupère la valeur précédente if ((etat==0) && ( (entree0==1) && (entree1==0)) ) sortie2=entree2; //Sortie3 est une AMZE unsigned char sortie3=(sortie>>3)&1; //récupère la valeur précédente if ((etat==1) && (entree2==0) ) sortie3=entree0; else if ((etat==2) && (entree2==1) && (entree0==0) ) sortie3=0; */ //codage de l'évolution de l'état switch (etat){ default: case 0: if ( (non_noir==1) && (present==0)) etat=1; else if (present==1) etat=9; break; case 1: if ( (metal==1) && (present==0)) etat=2; else if (present==1) etat=6; break; case 2: if (present==1) etat=3; break; case 3: if (plein==0) etat=4; break; case 4: if (plein==1) etat=5; break; case 5: if (plein==0) etat=0; break; case 6: if (plein==0) etat=7; break; case 7: if (plein==1) etat=8; break; case 8: if (plein==0) etat=0; break; case 9: if (plein==0) etat=10; break; case 10: if (plein==1) etat=11; break; case 11: if (plein==0) etat=0; break; } //pour le premier exercice: //sortie=0; //reconstruction de sortie à partir des variables intermédiaires //sortie=(sortie3<<3) | (sortie2<<2) | (sortie1<<1) | (sortie0<<0) ; //stoppeur est en logique inverse, la commande est pour rétracter le stoppeur sortie=((stoppeur_retracte)<<3) | (switch2<<2) | (switch1<<1) | (moteur<<0) ; } //////////////////////////////////////////////////////////////////// CStateMachine mae; ////////////////////////////////////////////////////// void setup(){ init_millis(); //boucle locale pour simu //int r=setupES("127.0.0.1","4242"); //arduino maison //int r=setupES("192.168.1.177","4242"); //arduino iut gomette bleue int r=setupES("172.16.6.60","4242"); setName("Bertrand etu"); if (r!=0) printf("erreur ouverture socket\n"); printf("Elapsed time: %ld milliseconds\n", millis()); } ////////////////////////////////////////////////////// void loop(){ /* for (int nbrport=0;nbrport<10;nbrport++){ writePort(123+nbrport); unsigned char e=readPort(); //std::cout << e << endl; }*/ unsigned int periodiciteTache1=10; static unsigned long timerTache1 = millis(); if (millis() - timerTache1 >= periodiciteTache1) { timerTache1 += periodiciteTache1; mae.setEntree(readPort()); mae.clock(); writePort(mae.getSortie()); char chaine[100]; sprintf(chaine,"etat %d", mae.getEtat()); setMsg(chaine); } /* unsigned int periodiciteTache2=1000; static unsigned long timerTache2 = millis(); if (millis() - timerTache2 >= periodiciteTache2) { timerTache2 += periodiciteTache2; static unsigned int cpt=0; cpt++; char chaine[100]; sprintf(chaine,"cpt=%d",cpt); printf(chaine); setMsg(chaine); } */ } Programme de test étudiant à vérifier: /*! \file sketch.cpp \brief Emulation sketch Arduino pour le CESI. \author Bertrand Vandeportaele IUT GEII \date 14/02/2022 */ #include "sketch.h" #include "lib_io_tp.h" ////////////////////////////////////////////////////// //! fonction d'affichage d'un message de debug bien pratique, //! qui affiche un message texte, le nom du fichier et le numéro de la ligne //! depuis où la fonction a été appelée void debugMessage(const char * chaineMsg,const char * chaineFile,const unsigned int line){ printf("DEBUG %s : l %d : %s\n",chaineFile,line,chaineMsg); flush(std::cout); } ////////////////////////////////////////////////////// void programmeDeTest1(){ //! Le composant à tester CStateMachine mae; printf("Test lancé le "); printf("%s",__DATE__ ); printf(" à "); printf("%s",__TIME__ ); printf("\nFonction de test: "); printf(__func__); //boucle pour gérer les différents cas à tester int ntest=1; printf("début du test numéro: "); printf("%d\n",ntest); mae.reset(); mae.setEntree(0xFF); //OxF mae.clock(); //ici on teste la mae sans considération de timing, donc clock() n'est pas conditionné à un timer if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); //passage à l'etat 1 if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); //passage à l'etat 2 if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=2) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); //passage à l'etat 3 if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=3) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); //passage à l'état 4 if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=4) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1);//passage à l'etat 0 mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //boucle 5,6,7,8 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); //passage à l'etat 1 //Compléter le test ici if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); //passage à l'etat 5 if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=5) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); //passage à l'etat 6 if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=6) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); //passage à l'état 7 if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=7) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1);//passage à l'etat 8 mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=8) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1);//passage à l'etat 0 mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); //boucle 9,10,11 mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 0 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); //passage à l'etat 9 //Compléter le test ici if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=9) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); //passage à l'etat 10 if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=1) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,1); mae.clock(); if (mae.getEtat()!=10) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); //passage à l'etat 11 if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); if (mae.getSortieBit(0)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(1)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(2)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 if (mae.getSortieBit(3)!=0) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); //etat 1 mae.setEntreeBit(0,0); mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,0); mae.setEntreeBit(2,1); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1); mae.setEntreeBit(1,1); mae.setEntreeBit(2,0); mae.setEntreeBit(3,0); mae.clock(); if (mae.getEtat()!=11) debugMessage("Erreur: La MAE n'est pas dans l\'état prévu", __FILE__, __LINE__); mae.setEntreeBit(0,1);//passage à l'etat 0 mae.setEntreeBit(1,1); mae.setEntreeBit(2,1); mae.setEntreeBit(3,1); mae.clock(); exit(0); //commenter cette ligne pour ne pas quitter le programme après la fin du test } ////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //Implémentation de la méthode constructeur CStateMachine::CStateMachine(){ // à compléter si besoin, allocation etc... reset(); } //////////////////////////////////////////////////////////////////// //Implémentation de la méthode reset, tout ce qui est fait pour (re)démarrer la machine à états void CStateMachine::reset(){ etat=0; sortie=0; //mettre des valeurs initiales correctes } //////////////////////////////////////////////////////////////////// //Implémentation de la méthode clock void CStateMachine::clock(){ //variables intérmédiaires pour les entrées unsigned char P_non_noir=(entree>>2)&1; unsigned char P_metallique=(entree>>1)&1; unsigned char P_presente=(entree>>0)&1; unsigned char G_pleine=(entree>>3)&1; unsigned char moteur = (sortie>>0)&1; unsigned char sw1 = (sortie>>1)&1; unsigned char sw2 = (sortie>>2)&1; unsigned char stoppeur = (sortie>>3)&1; //variables intérmédiaires pour les sorties //codage des sorties //Sortie0 est une AMZI if (etat==4 || etat==8 || etat==11) moteur = 0; else moteur = 1; if (etat==10)//tous les switchs sont ouverts { sw1=0; sw2=0; } else if (etat==7) { sw1=0; sw2=1; } else if (etat==3) { sw1=1; } else { sw1=0; sw2=0; } if ((etat==11)||(etat==4)||(etat==8)) { stoppeur=0; } else { stoppeur=1; } //codage de l'évolution de l'état switch (etat){ default: case 0: if (P_non_noir==0) etat=1; else if (P_presente==0) etat=9; break; case 1: if (P_metallique==0) etat=5; else if (P_presente==0) etat=2; break; case 2: if (G_pleine==1) //piece grise etat=3; break; case 3: if (G_pleine==0) etat=4; break; case 4: if (G_pleine==1) etat=0; break; case 5: if (P_presente==0) //piece rouge etat=6; break; case 6: if (G_pleine==1) etat=7; break; case 7: if (G_pleine==0) etat=8; break; case 8: if (G_pleine==1) etat=0; break; case 9: if (G_pleine==1) //piece noire etat=10; break; case 10: if (G_pleine==0) etat=11; break; case 11: if (G_pleine==1) etat=0; break; } //reconstruction de sortie à partir des variables intermédiaires sortie=(stoppeur<<3) | (sw2<<2) | (sw1<<1) | (moteur<<0) ; } CStateMachine MAE; //////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////// void setup(){ init_millis(); //boucle locale pour simu int r=setupES("127.0.0.1","4242"); //arduino iut gomette bleue //int r=setupES("172.16.6.60","4242"); setName("Xanxo Besse"); if (r!=0) printf("erreur ouverture socket\n"); printf("Elapsed time: %ld milliseconds\n", millis()); programmeDeTest1(); } ////////////////////////////////////////////////////// void loop(){ unsigned int periodiciteTache1=20; static unsigned long timerTache1 = millis(); if (millis() - timerTache1 >= periodiciteTache1) { timerTache1 += periodiciteTache1; MAE.setEntree(readPort()); MAE.clock(); writePort(MAE.getSortie()); char chaine[100]; sprintf(chaine, "Etat=%d", MAE.getEtat()); printf(chaine); setMsg(chaine); } unsigned int periodiciteTache2=1000; static unsigned long timerTache2 = millis(); if (millis() - timerTache2 >= periodiciteTache2) { timerTache2 += periodiciteTache2; static unsigned int cpt=0; cpt++; char chaine[100]; sprintf(chaine,"cpt=%d",cpt); printf(chaine); setMsg(chaine); } }