Il m'est arrivé plus d'une fois, lorsqu'un programme ne faisait pas ce que je voulais, de décrire à mon collègue (je n'en avais qu'un) le déroulement / fonctionnement de mon programme.... et de trouver la solution au problème.
Version imprimable
Coucou tout le monde :coucou:
Coucou bacelar ;)
Ta proposition de TRACE() avec _T est spécifique à Windows; or, je crois que le "poster" tourne sur "RPI", du Linux donc.
Ça fait très longtemps que je n'ai pas pratiqué, mais j'ai souvenir d'une bibliothèque multiplateforme qui fait le job, "spdlog".
Si l'on ne veut pas s'encombrer avec, voici une version sommaire et portable de "TRACE()". Elle s'activera lors d'un "Build" (construction) de type "Debug".
Je viens d'ajouté "sommaire" parce que tu as très justement abordé le problème du "flood" du terminal. À ce sujet, dans la version plus complète que j'avais écrite, il y avait du TRACE à toutes les sauces: TRACE_RED, TRACE_GREEN, etc., TRACE_LEVEL, TRACE_WARNING, TRACE_TITLE, TRACE_BEEP, etc., etc., et effectivement ça aide pas mal.
Mais encore une fois, "spdlog" peut faire le job.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 //Overview of a C++ TRACE() implementation //This header must be included before all others in each source file. #pragma once #if ! defined NDEBUG #define DEBUG_MODE_ENABLED 1 #else #define DEBUG_MODE_ENABLED 0 #endif enum {debug_mode_enabled= DEBUG_MODE_ENABLED}; #include <cstdio> //Variadic Macros, officially since C++11 (and C99 for info), but maybe before as compiler extension #define TRACE(...) do {if (debug_mode_enabled) std::fprintf(stderr, __VA_ARGS__);} while(0) //Must be used like printf(), for example: //TRACE("Hello, %s!", "trace");
En tout cas c'est un comportement indéfini, et sur PC, généralement un segfault.
C'est peut être une coquille, mais je compte 4, voire 6 autres problèmes.
Aussi dans le deuxième code, std::make_unique peut lancer une exception. Mais, contrairement au premier, ce n'est pas souligné. Ça laisse croire que la gestion des exceptions devient inutile avec les "smart pointers". En l'état, les deux codes ne sont pas comparables.
L'appareil que j'utilise à cet instant ne permet pas la consultation des PDF en pièces jointes. Des images et du texte dans le corps des messages auraient été préférables.
Je ne vais pas épiloguer sur les difficultés du langage C++ mais il ne faut pas se priver d'en explorer d'autres. Plus on est à l'aise avec un langage et mieux c'est, si c'est un langage qu'on aime, c'est encore mieux.
Cela dit, le fait d'avoir déjà un projet est un atout. Il faut sélectionner une portion de C++ qui va bien, quelques briques logiciel, et ce sera sur les rails.
Mais ATTENTION!!! L'aspect sécurité des personnes est ici primordial. Si vous n'êtes pas en mesure de l'assurer côté matériel, ne vous engagez pas dans cette voie. Je passe sous silence les problèmes de normes, réglementations, certifications pour lesquels vous êtes certainement au fait. Mais surtout, pensez à bien vérifier votre marge de manoeuvre par rapport à votre contrat d'assurance habitation. Ce genre de négligence ne pardonne pas.
Pour en revenir à l'objet de la discussion, si je traduis bien, il y a deux systèmes chaud, froid, et le but est qu'ils ne fonctionnent pas en même temps. Ensuite apparaissent les soucis de la mise en forme de tout ça. J'y reviendrais.
Pour le premier point, le plus accessible pour un débutant c'est encore de coller à la réalité. Quand il y a un système de chauffage et un autre de climatisation, généralement, il y a un surensemble qui gère le tout, plus ou moins. Le "plus ou moins" c'est parce qu'il existe un troisième système asservi qui est le thermostat d'ambiance.
Son rôle est de réclamer la production de chaleur ou de fraicheur en fonction de sa programmation et des températures des milieux dont il a la charge.
Pour ce qui est du transport et de la distribution de cette énergie produite, les manières de faire sont tellement nombreuses que, dans les faits, ce n'est qu'une extension du système.
Bref, ce surensemble peut s'appeler une pompe à chaleur, un climatiseur réversible, une bouillote... qu'importe ...
Du point de vue du code, ça pourrait donner ce genre de composition: (c'est du vrac, une illustration)
Je fais l'effort d'y mettre un peu de français pour ne pas perdre l'intéressé.
Cette classe n'a pas besoin d'être plus fournie. Comme énoncé précédemment, j'ai anticipé le problème des "while (1)", de Qt (qui peut être invasif), et la façon dont l'intéressé aborde ces choses. En effet, il y a souci de partage des responsabilités et d'orchestration du tout.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 class Froid; class Chaud; enum Mode {OFF, CHAUFFAGE, CLIM, AUTO, MAINTENANCE}; enum class Sub_Mode_Chauffage {ECO, COMFORT}; // dans l'optique du patron "stratégie" introduit par Bacelar //... class PAC // pompe à chaleur { public: void enable_chaud() {froid.disable(); chaud.enable();} void enable_froid() {chaud.disable(); froid.enable();} void disable() {froid.disable(); chaud.disable();} std::string get_status() const { return froid.get_status()+ " | "+ chaud.get_status();} //void set_mode(Mode m) {mode= m;} //... private: Chaud chaud; Froid froid; //integrated thermostat //Sonde exterieur{id_abc}; // //Sonte interieur{id_def}; //Sonde sejour{id_ghi}; //and/or maybe //Thermostat remote_thermostat; //... std::atomic<Mode> mode{OFF}; // => #include <atomic> };
Compte tenu des bouts de codes écrits par le "poster", je pense qu'il sera plus à l'aise avec une architecture MVC (model-view-controler, modèle-vue-contrôleur).
La vue, c'est l'interface utilisateur, le contrôleur, c'est l'objet PAC, le modèle serait une ou plusieurs structures/classes de données (), intégré à PAC, ou pas, alimenté par ce dernier, et utilisé par la machine à états.
Elle-même pourra y écrire des données qui seront lues par PAC, éventuellement aussi par un terminal de monitorage. Il y a de quoi faire, tout dépend du degré de sophistication recherché.
très schématiquement:
par exemple, PAC::Mode peut être considéré comme un modèle. (conf. la ligne avec Mode mode{OFF}; )Code:view(s) <-> controler(s) <-> model(s) <-> (finite-state) machine ( |hardware)
Cette fonction (qui s'appelle un arbre de décision), en même temps qu'elle s'allongera, vous ressentirez le besoin de factoriser.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 void run_machine(const PAC& pac) { //may be (later) PAC member function: void PAC::run_machine() { // or void run_machine(const Model& model) { //Trace only when the state changes //something like: auto trace_condition{ __LINE__ }; // <= (reminiscence) TRACE_CONDITION_INIT(optional_condition_type(BASIC | TREE), opt_name, opt_condition); while (pac.get_mode() != SHUTDOWN) { //or (model.mode != SHUTDOWN) // or ( ! must_exit()) std::this_thread::sleep_for(std::chrono::seconds(1)|1s); //prevent high CPU load if (pac.termostat.wath_requested() == Request::heating) { if (pac.get_mode() == CHAUFFAGE) { //auto debug_mode_enabled= DEBUG_MODE_ENABLED & (__LINE__ != trace_condition); trace_condition= __LINE__; // <= TRACE_CONDITION_NOTRACE_ON_MATCH(..); _ON_MISMATCH(...); TRACE("Production et acheminement de la chaleur en cours...\n"); TRACE("Utilisation de l'algo %s...\n", (pac|termostat).get_sub_mode_chauffage_name()); } else { //TRACE_CONDITION_NOTRACE_ON_MATCH(..) TRACE("Production de chaleur requise par le thermostat, mais interdite par le PAC.\n"); } // .... } turn_off_hardward(); }
Il s'en dégagera très vite des unités logiques, que vous pourrez modéliser, dans de simples fonctions ou en classes pour avoir quelque chose de "SOLID" (conf. définition sur Wikipedia) suivant vos progrès, évidemment.
Par ailleurs, c'est aussi une forme simple de machine à états, elle permettra de faire comprendre votre raisonnement et à vous de vous organiser, avec l'impératif que la boucle doit tourner continuellement, donc pas d'autre "pause" que le seul std::this_thread::sleep_for déjà en place.
Une bibliothèque d'automate simple toute faite aurait été préférable, mais je n'en connais pas. Faute de mieux, vous pourrez au moins avancer sur votre projet.
Bon, il faut que j'abrège.
Peut-être un mot pour la temporisation, qui peut se faire avec un chronomètre
Pour avoir quelque chose de rapidement fonctionnel, utilisez les threads (fils d'exécutions) (c++20 std::jthread).Code:
1
2
3
4
5 start= std::chrono::steady_clock::now(); // => #include <chrono> ... if (this_state_is_in_progress()) { if (std::chrono::steady_clock::now() - start > tempo) {set_next_state();} } //
Éventuellement, des fonctions libres. Faites tout dans un seul et même fichier (.cpp) pour garder une vue d'ensemble.
Déplacez au fur et à mesure les blocs de code "matures" qui vous en empêchent.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 void input(PAC& pac) { //input interface, std::cin, IHM: TUI (ncurses), GUI (frameworks Qt, wxWidgets, ImGUI), Interface-Machine-Machine (IPC...), RPC, ... while (wait_for_user_request && user_request != exit_request) { pac.deal_with(user_request); } //maybe at first: pac.set_mode(SHUTDOWN); } void output(const PAC& pac) { //ouput interface, std::cout, IHM widgets... while (waiting_for_signal, _for_callback or _for_countdown*) //* = polling (scrutation) output_interface(pac.get_status()); } int main() { PAC pac; auto machine{std::jthread{run_machine, std::ref(pac)}}; // => #include <thread> auto output_view{std::jthread{output, std::ref(pac)]}; input(pac); }
PS @Les-poteaux
Je viens de taper sur un minuscule clavier... donc, désolée pour les fautes...
Oui parce qu'à la base, je voulais juste faire un petit coucou ... ;)
Allez, @++
merci a vous tous ,
la comprehension de kaitlyn sur mon projet est au top ! merci.
apres , j'aimerai commencer peut-etre par revoir le code des DS18B20 pour comprendre petite a petit (doucement mais surement) .
au final j'ai changer la bibliotheque de mes pins , je vais utiliser WiringPi (tres connu).
puis la methode de TRACE me plait bien , mais en vous lisant j'ai essayer de l'inclure dans mon code , mais je ne vois pas trop comment faire pour le compiler avec cmake , si vous avez un exemple merci .
je vous remerci a tous du temps que vous m'accorder.
Salut tout le monde,
Pour intégrer TRACE() à ton projet, il suffit de copier le code correspondant dans un fichier d'entête (.h), ensuite d'inclure ce dernier dans tous tes fichiers sources (.cpp) et avant toutes les autres inclusions.
Code:
1
2
3
4
5
6
7 #include "le_fichier_de_trace.h" /* il contient le code précédemment présenté. */ #include <blablabla> //ect int main() { TRACE("je trace..."); }
Le fichier d'entête ne changera rien par rapport à CMake, ce n'est pas une source, il ne peut pas être compilé.
De même, je n'ai pas d'exemple de CMake à te fournir, car j'imagine que c'est en rapport avec Qt.
Cependant, une rapide recherche montre qu'il y a ce qu'il faut sur leur site :
https://doc.qt.io/qt-6/cmake-get-started.html
https://doc.qt.io/qt-6/cmake-manual.html
Salut,
J'ai une petite anecdote sympa.
Hier soir, j'ai visionné le 4e opus de la saison 3 de Foundation, une adaptation des romans d'Isaac Asimov.
Le Frère au Grand Jour (l'Empereur Cléon) s'adresse à Demerzel (androïde féminin) en ces termes (de mémoire):
Pour le contexte, Demerzel a effacé la mémoire de l'amoureuse de Cléon, puis l'a congédiée. Il est très en colère.
Citation:
Cléon: Sais-tu ce que c'est que d'avoir une connexion profonde avec l'être aimé ?
Citation:
Demerzel: Oui ! J'ai été conçue pour avoir des connexions avec mes semblables. On appelle ça l'entrelacement, au point de ne former qu'un.
:DCitation:
Cléon: Oh! Un peu comme un thermostat parle à une chaudière ? C'est vrai que c'est très intime. Au temps pour moi.