pointeurs structure union, lequel choisir

bonjour a tous Pour mon projet de domotique, je souhaiterais utiliser un tableau de char de taille fixe pour la communication sans fil de 32 octets. Pour différencier les différents types de module, je voudrais mettre un code dans le 1er octet et que la suite soit différent en fonction du module. Au depart, je pensais faire une structure pour chaque type de module et faire un CAST de ce que je recevais en fonction du 1er octet. Mais apparement, on ne peut pas faire de CAST avec une structure.

struct st1{
  char b;
  char a;
}s1;

struct st2{
  int c;
}s2;


void setup() {
  Serial.begin(9600);
  Serial.println("test union");
  s1.a=0x12;
  s1.b=0x34;
  Serial.println((st1)s2.c, HEX);

}

void loop() {
  
}

Ca ne compile pas et me retourne

Test_CAST_Struct_001.ino: In function 'void setup()': Test_CAST_Struct_001:16: error: no matching function for call to 'st1::st1(int&)' Test_CAST_Struct_001.ino:1: note: candidates are: st1::st1() Test_CAST_Struct_001.ino:1: note: st1::st1(const st1&)

Du coup, j'utilise un UNION en complement avec des #define pour simplifier l'ecriture.

struct st1{
  char b;
  char a;
};

struct st2{
  int c;
};

 union un1{
   st1 s1;
   st2 s2;
 };

 un1 u;
#define var1 u.s1
#define var2 u.s2

void setup() {
  Serial.begin(9600);
  Serial.println("test union");
  var1.a=0x12;
  var1.b=0x34;
  Serial.println(var2.c, HEX);

}

void loop() {
  
}

Il y a bien aussi les pointeurs que je voudrais utiliser pour ne pas avoir les données en double en mémoire, mais je suis un peu largué sur ce point.

Qu'elle est selon vous la meilleur solution? Avec UNION, ça fonctionne bien pour mon test, mais c'est pour savoir s'il y a mieux ou plus pratique. Je mettrais toutes les declarations dans un .h que j'inclurais dans les scketchs des différents modules pour avoir la meme chose pour chaque. Peut etre que j'utiliserais un numéro de version que je testerais pour les futures évolutions afin d'éviter les erreurs. comment peut-on initialiser une valeur directement dans la definition de la structure? (Edit)Je me reponds à moi même

struct data_struc{
  static const  byte version=1;  
...};

(Edit 2) bein non, ça ne fonctionne pas a cause du static const, ça ne reserve pas de mémoire réellement. 31 octets au lieu de 32 en faisant un sizeof(). Je vais devoir faire une variable et l'initialiser à chaque fois.

PS: en ecrivant ces lignes, je me rend compte que ce n'est pas si mal que ça en faite. :)

Merci de m'avoir lu et pour vos suggestions. a+

peut 'etre qu'un sprintf resoudrai ton probleme comme je comprent tu cherche a adition deux tableau de char c'est ça? si c'est ça alors essaye avec :

#define taille_max_carractere X // ou X est le nobre de caractere total de ton code +1
char buff[taille_max_carractere];
struct st1{
  char b;
  char a;
}s1;

struct st2{
  int c;
}s2;

void setup() {
  Serial.begin(9600);
  Serial.println("test union");
  s1.a=0x12;
  s1.b=0x34;
sprintf(buff,"%c%c%i ",s1.a,s1.2,s2.c);
  Serial.println(buff, HEX);

en suite a la reception tu peut faire un :

char buffReception[taille-max-caractere];
if( strcmp(buffReception, "Ton code module") == 0 )// ça cherche dans la reception une partie corspondand a ton code
                {
                    Serial.println("reception d'une clef ton code module");
                    }

bon c'est a la grosse mais ça devri fonctioné apres si ton code ne contien que 1 caracter au debut de la reception on peut faire plus simple :)

Salut,

Je pense que tu te prends les pieds dans le tapis tout seul. D'ailleurs je comprend pas bien ton problème à l'origine, et encore moins ce que tu comptait faire avec Serial.println((st1)s2.c, HEX);

Merci mais non. Mon projet consiste a faire dialoguer plusieurs modules de nature différente (capteur T°, Humidité, commande lumiere , volet, ...) avec une centrale domotique avec des nRF24L01+. Tous les modules envoient 32 octets à la centrale qui traite les données suivant un code ID propre à chaque type de module.

Je n'ai pas la structure avec moi pour l'instant mais elle est bien plus complete que l'exemple plus haut. exemple :

//module Volet
struct VOLET_T{
  byte ID;
  byte actionEnCour;
  int hauteur;
  char nomAction[28];   //pour avoir une taille de 32o
}

//module capteur de temperature et humidité
Struct CAPTEUR_HT{
  byte ID;
  int Temp;    //Temp *10
  int Humi;    //Humidité *10
  char txt[27];   //Pour une taille de 32 o
}

// la centrale domotique utilise ceci et fait la différentiation grâce au code ID.
union Centrale {
  VOLET_T volet;
  CAPTEUR_HT ht;
}centrale;

comme ça; avec le UNION des 2 structures, avec la même quantité de mémoire, je peux accéder aux bonnes données suivant l'ID. si ID=1 alors module VOLET si ID=2 alors module capteur Temp humidité

J’accède à la température si ID=2 avec "int temperature=centrale.ht.Temp;" ou à la hauteur du volet si ID=1 avec "int hauteurVolet=centrale.volet.hauteur;" alors qu'en mémoire, les données utilisent certaines cellules en commun. Bien sur, si je n'accede pas avec la bonne variable, les données ne sont pas cohérentes.

Je ne sais pas si je suis clair!

Pour avoir testé et être partie sur cette voie ci, je peux dire que ça fonctionne plutôt bien pour l'instant. Je croix que rien que le fait d'avoir publié le 1er message m'a convaincu d'utiliser cette solution.

Merci quand même

Je publierais ma structure complète actuelle des que je rentre chez moi.

A+

B@tto: Salut,

Je pense que tu te prends les pieds dans le tapis tout seul. D'ailleurs je comprend pas bien ton problème à l'origine, et encore moins ce que tu comptait faire avec Serial.println((st1)s2.c, HEX);

Ce code ne servais que pour faire un teste de faisabilité et ne servait donc a rien. Voir le post précédent où j'essai de mieux expliquer mon utilisation.

Et avec mes structures actuelles que je posterais plus tard, ça sera aussi je pense plus facile pour comprendre.

merci a+

Je vois ce que vient faire l'union alors, suffit de faire :

//module Volet

typedef struct VOLET_T{
  byte ID;
  byte actionEnCour;
  int hauteur;
  char nomAction[28];   //pour avoir une taille de 32o
};

//module capteur de temperature et humidité
typedef struct CAPTEUR_HT{
  byte ID;
  int Temp;    //Temp *10
  int Humi;    //Humidité *10
  char txt[27];   //Pour une taille de 32 o
};

// la centrale domotique utilise ceci et fait la différentiation grâce au code ID.
struct Centrale {
  VOLET_T volet;
  CAPTEUR_HT ht;
}centrale;

J'ai bien vu le "typedef" devant de "struct". Ca permet de faire des cast sur des structure perso ?

B@tto: ...

struct Centrale {
  VOLET_T volet;
  CAPTEUR_HT ht;
}centrale;

Si je fais ceci, les données "volet" et "ht" seront mis bout a bout. ce n'est pas ce que je souhaite.

a+

Voici les structures pour la transmission et pour la reception

//Version des structures des modules (TOUS les modules doivent avoir le meme code pour accepter les données reçus
#define VERSION_DATA 1                   //Version de la structure generale

//Definition des codes TYPE de MODULE
#define CODE_TYPE_MODULE_VOLET 0x10
#define CODE_TYPE_MODULE_PORTEGARAGE 0x20
#define CODE_TYPE_MODULE_LUMIERE 0x30
#define CODE_TYPE_MODULE_TEMPERATURE 0x40
#define CODE_TYPE_MODULE_HUMIDITE 0x50
#define CODE_TYPE_MODULE_ANEMOMETRE 0x60
#define CODE_TYPE_MODULE_CAPTEURALARME1 0x70
#define CODE_TYPE_MODULE_CAPTEURALARME2 0x80
#define CODE_TYPE_MODULE_AUTRE 0x90
#define CODE_TYPE_MODULE_TOUS 0xF0					//Pour envoyer à tous les modules en meme temps

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////   VOLET     //////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Struture pour la reception de la centrale vers le module VOLET
struct data_volet_R{
// Variables communes (7)
  byte version;          							//Version de la structure generale
  byte codeModule;									//Code pour différencier les types de module(0xF0) et leur numéro d'ID (0x0F)
  byte command;                        				// code de commande commune de tous les modules (=0x00 en fonctionnement normal)
  char nomModule[5];         						// Nom du module sur 5 caracteres
// Variables propres au module  
  byte codeAction;                      // code de l'action a effectuer
  byte codeErreur;                           // code de l'erreur s'il y en a (sinon, = FALSE)
  byte arg1;                            // argument 1
  byte arg2;                            // argument 2
// Variables complementaires pour avoir 32 octets en tout
  char donnees[20];                        //Données brutes
  
};

//Struture pour la transmission du module VOLET vers la centrale
struct data_volet_T{
// Variables communes (7)
  byte version;          							//Version de la structure generale
  byte codeModule;									//Code pour différencier les types de module(0xF0) et leur numéro d'ID (0x0F)
  byte command;                        				// code de commande commune de tous les modules (=0x00 en fonctionnement normal)
  char nomModule[5];         						// Nom du module sur 5 caracteres
// Variables propres au module  
  byte codeAction;                            // code de l'action en cour
  byte codeErreur;                           // code de l'erreur s'il y en a (sinon, = FALSE)
  byte arg1;                          		  // argument 1
  byte arg2;                          		  // argument 2
// Variables complementaires pour avoir 32 octets en tout
  char nomAction[20];                         //Nom de l'action en toute lettres (max 19 + \0) ou de l'erreur si codeErreur!=FALSE
  
};



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////   CENTRALE   /////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Pour la centrale TRANSMISSION (centrale --> module)
union data_centrale_T{
	data_volet_R volet;
};

//Pour la centrale RECEPTION (module --> centrale)
union data_centrale_R{
	data_volet_T volet;
};

dans le scketch du module VOLET, je declare :

  data_volet_R dataR;     //Pour la reception de données sur nRF24L01+
  data_volet_T dataT;     //Pour la transmission de données sur nRF24L01+

et pour la centrale :

data_centrale_R dataR;   //pour la reception des données nRF24L01+
data_centrale_T dataT;   //pour la transmission des données nRF24L01+

En tout cas, je suis satisfé du resultat.
a+

Hello,

Je ne vois pas l'utilité de passer par un union... définis ton struct avec typedef et tu pourras utiliser ton struct tel quel.

+1

je comprend vraiment pas ce qui te gêne ...

Désolé, j’ai vraiment du mal à m’expliquer.

Quand la centrale reçoit des données d’un module, elle reçoit 32 octets.
Les infos contenues dans ces octets ne sont pas formaté de la même manière suivant les types de modules.

J’utilise les UNION pour faire la distinction des variables des différent type de module grâce au “codeModule” et je sélectionne la sous structure adequate en fonction du code module.

Je suis partie sur un UNION car au départ, je n’arrivais pas a faire de cast sur une structure. Je referais un test ce soir avec la directive “typedef” devant et en utilisant des pointeurs. Mais sur ce coup la, je pense que UNION est tout indiqué pour faire ça simplement, certes avec des noms un peu plus long mais sans se torturer l’esprit avec des cast et pointeurs.

Il est vrai que pour l’instant, je développe mon 1er module (Volet) et n’ai qu’une seul structure pour la centrale car avec les interrupteurs de commande des volets que j’ai mis en attente, je ne peux pas les arrêter au milieu de la fenêtre. Donc je me concentre sur celui ci. Apres, je passe au module lumière. Après, je verrais pour les autres modules, surement la centrale connectée pour la commande avec la tablette et faire des scénarios.

Ca fonctionne bien dans ma tête mais c’est dure à faire sortir en explications.
A+

Je viens de refaire un test avec les typedef struct…

typedef struct st1{
  char b;
  char a;
};

typedef struct st2{
  int c;
};

void setup() {
  Serial.begin(9600);
  Serial.println("test union");
  st1 s1;
  s1.a=0x12;
  s1.b=0x34;
  st2 *s2=(st2*)&s1;     // <-- ligne en plus donc pointeur en memoire en plus
  Serial.println(s2->c, HEX);     //  <--  '->' a la place de '.' 
}
void loop() {}

Si je compare à UNION

  • Il y a une déclaration de pointeur en plus par type de module.
  • Il faut mettre ‘->’ a le place du ‘.’ ce qui m’obligerais a tout modifier lors de copier coller depuis ou vers les sketchs des différents module. Remarque : je dois quand meme modifier le nom des variables qui sont différentes du module et de la centrale.

Comme je le disais dans le post précédent, je prefaire utiliser “union” plutot que “struct” pour cette application ci.

Dans qu’elle cas sinon, doit-on utiliser le “UNION”.

a+

Il n'y a pas à choisir entre structure et union. Ce sont deux concepts complètement différents. Une structure définit un ensemble de variables hétérogènes qui forment un bloc contiguës de données en mémoires. La structure permet de manipuler le bloc de variables en passant simplement le pointeur sur la dite structure. Une union définit une zone de données hétérogènes qui partagent un même espace mémoire. L'union permet par exemple de manipuler un long sous forme d'octets en créant une union entre un long et un tableau de 4 byte.

Dans ton cas l'union est effectivement un bon choix puisqu'il permet de partager un espace mémoire commun pour y placer des données de type différents. Maintenant, intellectuellement, la solution n'est pas très élégante. Si tu ajoutes ou supprimes des senseurs ou bien si tu modifies le format des données tu vas devoir changer cette union. Je pense que la solution permettant le plus de souplesse et d'évolutivité serait que:

  • tu écrives une classe pour chacun des senseurs.
  • que ta routine de réception se contente de recevoir des byte
  • qu'en fonction du type de senseur identifié la routine de réception passe la main à la méthode de décodage associée à la classe du senseur en lui transmettant les données reçues.

Par rapport à l'union :

  • on utilise toujours qu'un tampon de réception.
  • Le programme principal ne connait pas et n'a pas à connaitre les types manipulés
  • les évolutions des senseurs sont complètement transparentes pour le programme principal

Bonjour

fdufnews: - tu écrives une classe pour chacun des senseurs. - que ta routine de réception se contente de recevoir des byte - qu'en fonction du type de senseur identifié la routine de réception passe la main à la méthode de décodage associée à la classe du senseur en lui transmettant les données reçues.

Ok. C'est vrai que je n'ai pas pensé aux passage des parametres a mes classes. Pour l'instant, je ne resonne pas assez 'classe' et, de plus, j'ai fait un code de test pour la transmission des ordres au module qui ne fait que ça pour ce module la exclusivement. Pas encore de classe pour la partie centrale. Pour le module, je suis parti directement sur une classe.

fdufnews: Par rapport à l'union :

  • on utilise toujours qu'un tampon de réception.
  • Le programme principal ne connait pas et n'a pas à connaitre les types manipulés
  • les évolutions des senseurs sont complètement transparentes pour le programme principal

Je devrais passer le tampon de reception par pointeur aux méthodes de classe mais du coup, je vais devoir faire un cast a chaque passage en fonction de qui il est destiné ou alors, il y a une astuce que je ne connais pas?

Merci pour tout, tu m'a bien evité des problémes pour la suite. J'y retourne

a+

Je devrais passer le tampon de reception par pointeur aux méthodes de classe mais du coup, je vais devoir faire un cast a chaque passage en fonction de qui il est destiné ou alors, il y a une astuce que je ne connais pas?

Le programme principal passe un pointeur à la méthode de décodage associé à la classe. Le plus simple étant de passer un pointeur non typé. Celle-ci fait un cast pour manipuler sa structure.

bonjour

fdufnews: Le programme principal passe un pointeur à la méthode de décodage associé à la classe. Le plus simple étant de passer un pointeur non typé. Celle-ci fait un cast pour manipuler sa structure.

Je croix que j'ai une idée de comment faire

void maFonctionDeDecodage( void * data){
  if (data.codeAction==ACTION_MONTER){
// Faire monter le volet
  ..
}
...
}

mais je ne sais pas où déclarer le type dans la fonction pour pouvoir utiliser le "data.codeAction".

Une petite aide ou indice serait le bienvenu.

Je referai des tests ce soir. Merci a+

Je verrais plus quelque chose comme

...
FaireMonter(Volet1);
...

void FaireMonter(VOLET *volet) {

SendTo(volet->ID,CODE_ACTION_MONTER); // SendTo() étant la fonction bas niveau qui permet la communication

}

a B@tto: mon exemple ci dessus était pour une communication dans l'autre sens, module vers centrale quand le module sera utilisé avec ses boutons physique près des fenêtres. Ca servira à faire du LOG et surtout, connaitre la position du volet pour l'interface graphique sur tablette.

1°) La centrale reçoit quelque chose et le dispatche suivant le codeModule dans la classe du module concerné qui va faire son propre traitement. La classe du module pourrait en retour, envoyer des données au module.

2°) La centrale peut aussi et bien sur envoyer des données (commande, paramétrage, ...) aux différents modules.

Tout le fil, pour moi, est basé sur le cas 1. J'aurais du le préciser des le départ.

Bonjour à tous
Après quelques jours d’absences, je continu mes tests.

//Definitions des strutures de données chacune dans sa propre class
typedef struct St1{
  char b;
  char a;
};

typedef struct St2{
  int c;
};


/Variables globales
char buf[2];

//Ces fonctions seront dans des classes distinctes
void afficheST1(void *tmp){
  St1 *tmp1=(St1*)tmp;
  Serial.print(tmp1->a, HEX);
  Serial.println(tmp1->b, HEX);
}

void afficheST2(void *tmp){
  St2 *tmp2=(St2*)tmp;
  Serial.println(tmp2->c, HEX);
}



// Prog principal
void setup() {
  Serial.begin(9600);
  Serial.println("test typedef et pointeur VOID");
  buf[1]=0x12;
  buf[0]=0x34;
  Serial.println("St1");
  afficheST1(&buf);
  Serial.println("St2");
  afficheST2(&buf);
}
void loop() {}

Ci dessus le genre de passage de parametres que je vais utiliser dans la centrale domotique (Ceci n’est qu’un exemple pour le test). Effectivement, le programme principale ne connait pas la definition des structures de données qui seront définies chacun dans sa class.

Merci de m’avoir mis dans la donne direction. J’aurais galérais à vouloir insister avec mon UNION.
a+

Hello,

Regarde du côté des méthodes virtuelles, si tu crées une classe abstraite dont vont hériter tes classes dérivées (polymorphisme), c'est une solution sûre et élégante.