Usage classe print

Bonjour à tous,

Je pense avoir bien compris le fonctionnement de la classe print et je souhaiterais l'intégrer dans la lib que je suis en train d'écrire pour interfacer avec les CC1101/CC430 en cross plaform Arduino + Energia.

Mon problème c'est qu'à l'inverse de la liaison série ou d'un pilotage de lcd, à la fin je dois envoyer une commande au module radio pour lui dire "fait partir le tout". Avec Serial pas de souci, tout est piloté en hard donc que ça soit le dernier caractère ou pas, la procédure est la même, on rempli le buffer. Mais dans mon cas ce n'est pas la même chose ... Je dois remplir le buffer et si c'est le dernier caractère alors il faut lancer la procédure d'émission. Et je ne vois pas de solution à mon problème car il semble qu'aucun code ne puisse être lancé en fin de print.

La seule option que je vois c'est créer une fonction print dans ma classe et à l'interieur cette fonction utiliser print de la classe stream. Mais la je bloque sur la syntaxe C++ à utiliser ....

hello,

As-tu des pointeurs vers la définition de la classe print ?

XavierMiller:
As-tu des pointeurs vers la définition de la classe print ?

Aie je savais bien que quelqu'un me sortirait quelque chose que je ne pigerais pas xD

Je pense que ça serait plus clair (pour moi surtout) de parler concrètement en code. Voici donc les parties qui nous intéresse ici, tirée de la lib HardwareSerial d'Energia (basé sur le core Arduino donc c'est quasiment la même chose) élaguée pour ne laisser que les parties qui nous interesse :

HardwareSerial.h

class HardwareSerial : public Stream
{
	public:
		virtual size_t write(uint8_t);
		using Print::write; // pull in write(str) and write(buf, size) from Print

};

HardwareSerial.cpp

size_t HardwareSerial::write(uint8_t c)
{

//code pour placé c dans le buffer

	return 1;
}

print.h :

class Print
{
  public:
    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); }
    virtual size_t write(const uint8_t *buffer, size_t size);
};

Print.cpp :

size_t Print::write(const uint8_t *buffer, size_t size)
{
  size_t n = 0;
  while (size--) {
    n += write(*buffer++);
  }
  return n;
}

size_t Print::print(const char str[])
{
  return write(str);
}

A recopier tout ça ensemble ça me semble de moins en moins clair ... Donc clairifions les choses d'abord : comme "tout le monde" utilise un write() ça devient assez compliqué de savoir qui est le write() de qui, et avec tous ces virtual difficile à un moment de savoir qui overload qui ... Et je suis pas encore bien familiarisé avec les règles de classe du C++, l'occasion de se perfectionner avec ce sac de noeud !

Donc arrête moi si me trompe, le write utiliser dans Print::write() ici n += write(*buffer++); est le write de HardwareSerial ? Ca me parait logique sinon Print ne pourrait pas s'utiliser dans n'importe quel classe.

Et à partir de la j'y comprend plus grand chose au sac de noeud ...

Je n'arrive pas à voir clairement... tu fais un using Print::write sans hériter, je ne connais pas cette construction : est-ce que ça compile ?

Ne pourrais-tu pas simplifier en définissant d'abord ce dont tu as besoin avant de commencer à vouloir implémenter sans trop savoir quoi ?

Ce que je te montre fonctionne, c'est tiré de la librairie Serial d'Energia (Arduino-like pour msp430 si tu ne connais pas).Mais peut-être que j'ai zappé une ligne importante, les codes complets :

Donc pour l'instant je n'ai rien implanté dans ma lib, j'essaye justement de bien comprendre comment les autres utilisent print pour pouvoir m'en inspirer. Grosso-modo je vois comment ça fonctionne : print() utilise le write() de la lib qui l'a appelé. Après pour le détail justement c'est la où je bloque, et donc c'est la où je bloque pour faire ce que je veux.

Apparemment, Stream hérite de Print

Ah oui boulette, donc on oublie stream. Mais ça n'enlève rien à mon problème :slight_smile:

J'ai pas compris vraiment ton problème, pourrais-tu essayer de le clarifier ?
Et en le clarifiant, tu trouveras probablement la réponse :wink:

xD ouais pas clair tout ça ... Et puis je viens de me rendre compte que HardwareSerial hérite de Stream, d'où ta remarque. Si en plus je me mets à ne plus suivre c'est sûr qu'on va pas s'en sortir ...

Déjà j'ai édité mon message précédent avec les fonctions pour ajouter un des print() pour mon raisonnement.

Je résume : HardwareSerial hérite de stream qui hérite de Print. Me trompe-je ?

Ensuite passons aux questions précises :

  • quand j'appelle Serial.print("Coucou") on appelle donc Print::print et dedans il y a un write() : celui la est-ce bien celui de la classe Print ?

  • si c'est bien ça, dans Print::write() utilise alors un autre write() celui de HardwareSerial j'imagine ? Comment est défini justement le fait que ça appelle ce write() la et pas Print::write ? Simplement le fait qu'il n'y a pas de proto pour write(uint8_t) ? On est d'accord ça ferait tourner en rond mais c'est pas ce qui arrête les compilateurs en général :wink:

En fait à force de relire je crois que je finis par comprendre comment ça se passe et pourquoi il faut autant de virtual. Il y a deux choses qui me turlupine vraiment concernant le HardwareSerial.h :

virtual size_t write(uint8_t) ==> pourquoi un virtual ? Simple précaution ?
using Print::write ==> utilité ? puisqu'il y a un write() dans HarwareSerial, Print::write() va se faire écraser ?

Hello,

Quand tu hésites, mets un serial.print unique dans chaque fonction pour savoir laquelle est bien utilisée :wink:

Sinon, je vois que tu ne sembles pas bien comprendre la notion d'héritage et de polymorphisme.

Héritage : quand une classe B hérite d'une classe A, B se comporte comme A avec des ajouts de méthodes et propriétés. Toute fonction publique de A peut s'appeler sur B. B peut aussi cacher des propriétés et méthodes de A en les redéclarant private ou protected.

De plus, B peut remplacer des méthodes de A, et quand on appelle B.méthodedeA(), c'est le code de B qui est alors utilisé.

Polymorphisme : quand on déclare une méthode "virtual" dans A, A devient "dynamique" (ou polymorphe). Si l'on utilise un pointeur vers A et qu'on appelle une fonction virtuelle, c'est la méthode de "l'enfant le plus bas" qui est appelée (par exemple B->maFonctionVirtuelle), si le pointeur vers A est en fait un B.

L'héritage permet d'acquérir un comportement (celui du parent), le polymorphisme permet de gérer un ensemble d'objets hétéroclites mais ayant la même interface (les méthodes virtuelles du parent commun).

Si tu aimes la lecture, je te conseille l'excellent livre "Desing Patterns Tête la Première" chez O'Reilly. C'est sur Java, mais la partie théorique (99% du bouquin) est commune au C++ et autres langages orientés objet.

Merci pour ta réponse !

A te lire j'avais quand même bien saisi héritage et polymorphisme, c'est plus le passage de la théorie à la pratique qui me pose problème et les "subtilités" de ces deux outils. J'avais dévoré les deux bouquins qu'on m'avait conseillé sur le C t le C++, va falloir que j'y replonge parce qu'en première lecture ça faisait pas mal d'info sans forcement voir l'intérêt sur le coup. Maintenant je le vois xD

Fais-toi quelques exemples avec des "print coucou" un peu partout pour bien capter :wink:
Et c'est pas nécessaire que ce soit sur Arduino, fais un tout petit programme console avec des std::cout << "coucou" << std::endl, :slight_smile:

Oui c'est le truc à faire en attendant que je termine de batailler avec mes CC1101 ...