Problème de taille d'une variable

Bonjour à tous.

J’essaye de comprendre pourquoi mon programe plante après 2 heures, mais pas après une heure.
Plus précisément, si j’envoie mes données toutes les heures, ca marche mais pas toutes les deux heures.

J’enregistre les évéenemtsn sur une carte SD, et je constate que ca plante au moment de l’envoi (via TTN LoRaWAN)

Etand donnée que j’ai augmenté le nombre de caratere à envoyé, je me demande si je ne surcharge pas mon buffer. De toute évidence oui, mais certain élément me dise que non.

Je m’explique.

Je déclare mon buffer 'payload ainsi:

const uint8_t payloadSize = 64;
static uint8_t payload[payloadSize];

Donc sauf erreur, je peux avoir 64 caracteres. non?

Alors que ma chaine de caratère en a 87.

{ba:458,te:-1,pr:-1,al:-1,hu:-1,mo:-1,lu:-1,w1:45,w2:-1,w3:-1,da:0,aq:-1,ts:-1,ga:0,wi:0}

MAis en réalité les données à envoyés son converti en hexa. Ce qui est réellement envoyé est ceci (sous payload =):

Values = {ba:582,te:-1,pr:-1,al:-1,hu:-1,mo:-1,lu:-1,w1:45,w2:-1,w3:-1,da:0,aq:-1,ts:-1,ga:0,wi:0}
Payload size: 21
Payload = {35 38 32 2C 2C 2C 2C 2C 2C 2C 34 35 2C 2C 2C 30 2C 2C 2C 30 2C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 }

Donc est-ce que le 21, correspond bien? Donc j’en conclu que mon buffer n’est pas surchargé puisqu’il y a encore dss 00

Ce qui me préoccupe, c’est que j’affiche ceci avant l’envoi

Serial.println(strlen(payload));

et il m’affiche 21!!!

Ne devrait-il pas m’afficher 87 ou du moins 64?

Ce qui me préoccupe, c’est que mon code fonctionnait très bien jusqu’à ce que j’ajoute 4 capteurs en plus, ce qui évidemment ajoute du contenu dans payload.

Mon code plante juste au moment de l’envoi, donc ou payload est lu pour l’envoi, ce qui me laisse à pensé que le problème est à ce niveau…

L’autre élément qui me trouble, c’est que lorsque je ,
converti mon hexa en string
pour lire le contenu de payload, je vois ceci

582,45,0,0,�������������������������������������������

Apèrs le derniere 0, ily a des losange noir avec un ?, ce qui laisseà croire que mon buffer n’est pas fermé avec un \0, ce qui est le cas. D’autant plus, comme je l’ai dit plus haut, ca fonctionnait très bien avant.

A partir de là, avez-vous deja un avis, un point de vue?

je pense qu’il vous faudra un peu plus de code, donc voici comment j’encapsule payload:

A savoir avant que ‘nbMaxCapteurs’ m’affiche 15, et ‘nbCapteurActif’ m’affiche 4

Nb capteurs: 15
Nb capteurs actifs: 4

j’ai vérifier et ‘mesCapteur’ peut bien avoir 15 capteurs:

capteur mesCapteur[] = {
  {capteur_battery_id, battery_active, "ba"},
  {capteur_temperature_id, temperature_active, "te"},
  {capteur_pression_id, pression_active, "pr"},
  {capteur_alt_id, alt_active, "al"},
  {capteur_humidity_id, humidity_active, "hu"},
  {capteur_moisture_id, moisture_active, "mo"},
  {capteur_luminosity_id, luminosity_active, "lu"},
  {capteur_wm1_id, wm1_active, "w1"},
  {capteur_wm2_id, wm2_active, "w2"},
  {capteur_wm3_id, wm3_active, "w3"},
  {capteur_datetime_id, datetime_active, "da"},
  {capteur_airquality_id, airquality_active, "aq"},
  {capteur_temperature_soil_id, temperature_soil_active, "ts"},
  {capteur_gauge_id, gauge_active, "ga"},
  {capteur_wind_id, wind_active, "wi"},
};

Et voici fonc comment j’encapsule mes données dans payload

uint8_t * ptr = payload;

        for (byte i = 0; i < nbMaxCapteurs; i++) {
          if (mesCapteur[i].actif) { // si le capteur n'est pas actif on n'imprime pas

            // PRINT LES MESURES MESUREES
            itoa(mesMesures[i][mesCapteur[i].idDuCapteur].valeur, (char *) ptr, 10); // on écrit à partir de ptr la représentation ASCII en base 10 de la valeur de ibatt
            ptr += strlen((char *) ptr);
        
            if (i < nbMaxCapteurs-1)
            {
              *ptr = ','; // virgule
              ptr += sizeof(char);
            }
            else
            {
              *ptr = 0 ; // Je ferme
            }
          }
          else
          {
            if (i < nbMaxCapteurs-1)
            {
              *ptr = ','; // virgule
              ptr += sizeof(char);
            }
            else
            {
              *ptr = 0; // Je ferme. Pas de bouger le pointeur
            }
          }
        }

        // DEBUG Affiche le contenu de payload
        Si.sprint(F("Payload size: "),2);
        int s =  strlen((char *)payload);
        Si.sprintln(s,2);
        Si.sprint(F("Payload = {"),0);
        for (byte i = 0; i < payloadSize; i++) {
          //Serial.print("0x");
          if (payload[i] <= 0xF) Si.sprint(F("0"),0);
        
          Si.sprint(payload[i], HEX, 0);
          Si.sprint(F(" "),0);
        }
        Si.sprintln(F("}"),0);

Je suis conscient que mes informations sont peut etre dur à cerné, mais si vous arriviez voir quelque chose d’intrigant, ou si vous pouviez me demander plus de précision, plus de code, n’hésitez pas.

En résumé:

  • Pourquoi, si j’envoie mes données toutes les heures ca marche, mais ca ne marche pas si j’augmente ce delai?
  • Est-ce que payload serait surchargé ou mal fermé avec un \0

Je vous remercie si vous arriiez me mettre sur un piste et je n’hésiterais pas à vous apporter un complément d’information en investigant :slight_smile:

Milles mercis
[/list]

Bonsoir,

quelques réponses à tes questions mais pas à toutes :

pierrot10:
Donc sauf erreur, je peux avoir 64 caracteres. non?

Oui

Alors que ma chaine de caratère en a 87.
MAis en réalité les données à envoyés son converti en hexa. Ce qui est réellement envoyé est ceci (sous payload =):
Donc est-ce que le 21, correspond bien? Donc j’en conclu que mon buffer n’est pas surchargé puisqu’il y a encore dss 00

Oui, car tu n’insères aucune valeur pour tes capteurs désactivés. Tu vas “exploser” ton buffer quand tu activeras plus de capteurs.

Ce qui me préoccupe, c’est que j’affiche ceci avant l’envoi

Serial.println(strlen(payload));

et il m’affiche 21!!!

Ne devrait-il pas m’afficher 87 ou du moins 64?

21 est cohérent. strlen s’arrète de compter dès le premier zero (marque de fin de chaîne) rencontré.

Ce qui me préoccupe, c’est que mon code fonctionnait très bien jusqu’à ce que j’ajoute 4 capteurs en plus, ce qui évidemment ajoute du contenu dans payload.

Mon code plante juste au moment de l’envoi, donc ou payload est lu pour l’envoi, ce qui me laisse à pensé que le problème est à ce niveau…

pas trouver d’explication. Tu ne dépasses à priori pas la taille dans ce cas.

L’autre élément qui me trouble, c’est que lorsque je ,
converti mon hexa en string
pour lire le contenu de payload, je vois ceciApèrs le derniere 0, ily a des losange noir avec un ?, ce qui laisseà croire que mon buffer n’est pas fermé avec un \0, ce qui est le cas. D’autant plus, comme je l’ai dit plus haut, ca fonctionnait très bien avant.

C’est normal car tu affiches tous les octets du payload, même ceux que tu n’as pas initialisés. Si tu ne veux pas voir ceux que tu n’as pas initialisé remplaces “for (byte i = 0; i < payloadSize; i++) {” par “for (byte i = 0; i < strlen(payload); i++) {”.

Bonne chance pour la suite !

Salut,
Merci pour ta réponse malgré les manques de précisions…

En effet, ce que j’ai surtout besoin de savoir c’est si mon buffer est plein ou pas.

Donc pour résumé

Serial.println(strlen(payload));

m’affiche 21, donc il me reste encore 23 “places”.

Ce qui me permet d’éliminer le doute que j’avais du cas ou mon programme s’arretait à cause du buffer trop plein

Oui, car tu n’insères aucune valeur pour tes capteurs désactivés. Tu vas “exploser” ton buffer quand tu activeras plus de capteurs.

Oui en effet. J’ai décidé de tous les activer en attribuant la valeur de 0 pour ceux qui sont inactif. J’ai aussi simuler le cas ou il avait tous une valeur, et j’arrive au dessous de 64.

Donc c’est bien, il me reste à vérifier mon buffer avec

Serial.println(strlen(payload));

C’est normal car tu affiches tous les octets du payload, même ceux que tu n’as pas initialisés. Si tu ne veux pas voir ceux que tu n’as pas initialisé remplaces “for (byte i = 0; i < payloadSize; i++) {” par “for (byte i = 0; i < strlen(payload); i++) {”

D’accord, super!

Ceci étant dit, tout ceci ne m’arrange pas car je croyais pister une piste pour résoudre mon problème :slight_smile:

Et je n’arrive pas à comprendre pourquoi il arrive envoyer toutes les heures, mais au delà, il plante juste avant

LMIC_setTxData2(1, payload, strlen((char *)payload)-1, 0);

C’est pourquoi j’ai tout de suite suspecter payload…

D’ailleur, cette remarque

C'est normal car tu affiches tous les octets du payload, même ceux que tu n'as pas initialisés. Si tu ne veux pas voir ceux que tu n'as pas initialisé remplaces "for (byte i = 0; i < payloadSize; i++) {" par "for (byte i = 0; i < strlen(payload); i++) {".

est super intéressante, car 1), je peux le faire pour l’affichage

// DEBUG Affiche le contenu de payload
        Si.sprint(F("Payload size: "),2);
        int s =  strlen((char *)payload);
        Si.sprintln(s,2);
        Si.sprint(F("Payload sizeof: "),2);
        int so =  sizeof((char *)payload);
        Si.sprintln(so,2);
        
        Si.sprint(F("Payload = {"),0);
        for (byte i = 0; i < strlen(payload); i++) {
          //Serial.print("0x");
          if (payload[i] <= 0xF) Si.sprint(F("0"),0);
        
          Si.sprint(payload[i], HEX, 0);
          Si.sprint(F(" "),0);
        }
        Si.sprintln(F("}"),0);

mais aussi pour l’empilation des données à envoyé

//Si.sprintln(F("\r\nEmpilations des valeurs capteurs"), 2);
        //Si.sprintln(F("---------------------------------------"), 0);
         memset(payload,'\0',payloadSize);
        uint8_t * ptr = payload;

        for (byte i = 0; i < nbMaxCapteurs; i++) {
 

            // PRINT LES MESURES MESUREES
            itoa(mesMesures[i][mesCapteur[i].idDuCapteur].valeur, (char *) ptr, 10); // on écrit à partir de ptr la représentation ASCII en base 10 de la valeur de ibatt
            ptr += strlen((char *) ptr);
        
            if (i < nbMaxCapteurs-1)
            {
              *ptr = ','; // virgule
              ptr += sizeof(char);
            }
            else
            {
              *ptr = ',' ; // Je ferme
            }

Sauf que la , je le fais différemment.
Ne serait pas intéressant de n’emvoyé QUE les données SANS les “00 00 00 …”?

Pou cela, ne faudrait-il pas que je réduise la taille de payload?

Je la déclare ainsi

const uint8_t payloadSize = 64;
static uint8_t payload[payloadSize];

Si

Serial.println(strlen(payload));

affiche 21, ou 76…

serait-il éfficient de réduire payload à

payload[21];

ce qui éviterait du chenil.

Le truc, c’est que je ne sais pas comment on réduit un char. En attendant de savoir si cette réflexion peut être efficace, je vais aller chercher cette cottection, car j’ai déjà vu qu’on poubait le faire

:slight_smile:

Ne serait pas intéressant de n'emvoyé QUE les données SANS les "00 00 00 .."?

C'est déjà ce que tu fais (cf strlen) dans :

LMIC_setTxData2(1, payload, strlen((char *)payload)-1, 0);

D'ailleurs au passage je ne comprend pas le -1 dans le strlen. Si la chaine à envoyer est (exemple bidon) "abc", strlen vaudra 3 et strlen-1 vaudra 2, donc tu n'enverras que "ab" ?!?

Tu n'envoies donc pas les caractères inutiles de ton payload.

Salut,
Merci pour ton message!!!!!

D'ailleurs au passage je ne comprend pas le -1 dans le strlen. Si la chaine à envoyer est (exemple bidon) "abc", strlen vaudra 3 et strlen-1 vaudra 2, donc tu n'enverras que "ab" ?!?

je me demande sérieusement si mon problème vient pas de là-

Je te confirme que mon programme plante exctement avant

LMIC_setTxData2(1, payload, strlen((char *)payload)-1, 0)

ou.. au moment de lancer cette fonction.

Je viens de voir le fichier example de la librairie
Arduino-lmic
et je vois ceci

LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
        Serial.println(F("Packet queued"));

Donc pour le -1, je ne sais pas quoi répondrepour le momenet, disons que j'ai repis l'exemple.
Mais pourquoi, j'ai changé sizeof() en strln(), je ne sais plus. Probalement une erreur de ma part.

Peut etre que je voulais qu'il tienne compte de la largeur des caracteres et pas de la taille du buffer.

Penses-tu que ca peut être la raison du bug?

Je viens de lancer un teste avec

LMIC_setTxData2(1, payload, strlen((char *)payload), 0)

sans le -1, mais je dois attendre 2 heures pour voir si ca plante.

Demain, j'essayerai avec sizeof et je verrai viens si ca plante ou pas.... :slight_smile:

Mais je précise ensore, quand je lance le programme, la premiere fois ca passe. Puis le programme "est en pose" pendant 2 heures, et il reprends les mesures pour les envoyer. C'est à ce moment là que ca plante avant

LMIC_setTxData2(1, payload, strlen((char *)payload-1), 0)

La frequence d'envoi dépend de

const unsigned TX_INTERVAL = 7200;  // 2h

En fait, rien ne marche

LMIC_setTxData2(1, payload, strlen((char *)payload)-1, 0)
LMIC_setTxData2(1, payload, strlen((char *)payload), 0)

ca plante à la deuxième tentative
et

LMIC_setTxData2(1, payload, sizeof(payload)-1, 0)

Ca, ca n'onvoi meme pasl a premiere fois. Du moin je n'ai pas le message

1475691: EV_TXCOMPLETE (includes waiting for RX windows)
COMPLETED in 4659ms

J'utilise
Arduino-mic

J'essaye " de revenir" en commentant mes derniers code afin de localiser l'issue, afin de savoir pourquoi, ca marche à une frequence de moins d'une heure, mais pas au-delà. Je ne sais pas ou est la limite car je n'ai pas essayé entre 1h et 2h, mais jesais qu'audelà de 1h, ca gub :frowning:

Salut SuperCC et tous

Est-ce que tu peux encore m'aider?
Je suis sûre que la maniere comment en encapsuler les données dans payload est une source du problème.
Peut-être aussi que je ne peux pas envoyer des données plus de toutes les heures, mais ca m'étonnerait.

Alors j'ai décidé de rafraichir mon code. Dele refaire dans un nouveau fichier et profiter de faire du nettoyage. Sovent on seretrouve avec un fichier améliorer.

Aussi, puisque payoad est un uint8_t et que mes librairies me retorune généralement du float que je converti en int puis je les mets dans payload qui est un uint_8, je vais tout faire en uint8_t, et surtout en hexa.

Par exemple, dans la prise de la temperature, je ne veux plus faire

float f_tem;
int i_temp
Si.sprint(F("Temp: "),2);
    f_tem = bme.readTemperature();
    Si.sprint(f_tem,2);
    Si.sprint(F("C"),2);//The unit for  Celsius because original arduino don't support speical symbols
    Si.sprint(F("\t"),2);
i_tem = (int)f_tem;

mais directement le mettre f_tem en uint8_t. La focntion readTemperature, me retourne un float, donc j'ai pas le chois, mais le problème que je recontre maintenant (prennant en compte que la temerature est de 26), est comment etre sure que u_tem, contient

32 35

et pas

26
  float f_tem, f_pre, f_alt, f_hum;
  uint8_t u_tem, u_pre, u_alt, u_hum;
  
    //get and print temperatures
    Si.sprint(F("Temp: "),2);
    f_tem = bme.readTemperature();
    Si.sprint(f_tem,2);
    Si.sprint(F("C"),2);//The unit for  Celsius because original arduino don't support speical symbols
    Si.sprint(F("\t"),2);
    u_tem = f_tem;
    Serial.println(u_tem);
    Serial.println(u_tem,DEC);

Ci dessus, les deux m'affiche 26.

Pour rappel.les données encapsulées dans 'payoad' doivent être de l'hexa

To send data back and forth over The Things Network you’ll need to use bytes. This guide will help you encode different types of data in as little bytes possible.

Comment bien mémoirés a valeur de 'u_temp' pour qu'on ait le même format et l'encapsuler dans

const uint8_t payloadSize = 64;
static uint8_t payload[payloadSize];

Aussi,contrairement à ce que je faisait avant, je ne déclarerai plus payload en tant que global, mais comme une variable local, dans la fonction qui récupère le valeur des capteurs et les envoi.
Ainsi, je pourrai définir la taille de payload (payloadSize), en fonction du nombre byte récoltés de mes capteurs. 'payload' sera détruire une fois la fonction terminée.

J'éviterai ainsi ceci

Payload = {35 38 32 2C 2C 2C 2C 2C 2C 2C 34 35 2C 2C 2C 30 2C 2C 2C 30 2C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 }

pour avoir

Payload = {35 38 32 2C 2C 2C 2C 2C 2C 2C 34 35 2C 2C 2C 30 2C 2C 2C 30 2C }

Le problème, que j'ai, c'est travailler avec des bytes (ou hexa) et passer les valeurs d'une variable à une autre.

par exemple

'u_tem' dans 'payload'
'u_hum' dans 'payload'
'u_lum' dans 'payload'

évidement, sans écraser la valeur précédente :slight_smile:

Donc, si je peux maitriser ceci
'f_tem' dans 'u_tem' ,c'est top.
ou encore mieux, directement dans 'payload',mais dans ce cas, 'payload' devra être global. Mais j'aimais bien le principe qu'elle soit détruite à la find de la fonction send_measures(), puis qu'elle recevra de nouvelles valeurs à la prochaine loop.

J'avais bien galèré, à l'époque :slight_smile:

milles mercis pour vos lumières!!

En fait si tout ce passe bien, je devrais pouvoir afficher la valeru de u_tem ainsi

Si.sprint(F("u_tem = {"),0);
    for (byte i = 0; i < strlen(u_tem); i++) {
      //Serial.print("0x");
      if (u_tem[i] <= 0xF) Si.sprint(F("0"),0);
        
        Serial.print(u_tem[i], HEX);
        Serial.print(F(" "));
    }

mais la je pars mal car je n’ai pas déclarer u_tem comme une array

uint8_t u_tem

je devrais la déclarer ainsi

uint8_t u_tem[x]

mais comment savoir la valeur de x, si on sait pas s’il fera 5 degré ou 25 degré (nombre de digit).

Par exemple, pour l’alitude ‘u_alt’, ca peut aller de 1m à 2000. de 1 à 4 digits…

uint8_t  u_alt[yyyy]

Ca je ne maitrise pas. :slight_smile:

ou je ne maitrise pas la bonne démarche :slight_smile:

float f_tem => uint8_t u_tem => uint8_t payload[]

Salut, je passe juste en coup de vent pour essayer de préciser quelques points qui pourraient t'aider.

Pour rappel.les données encapsulées dans 'payoad' doivent être de l'hexa

To send data back and forth over The Things Network you'll need to use bytes. This guide will help you encode different types of data in as little bytes possible.

l'hexa, la représentation en base 16, n'est qu'une représentation parmi d'autres, de la valeur d'octets. Ce que veut la fonction LMIC_setTxData2 ce sont des octets (bytes ou uint8_t) et elle se moque de la représentation que tu veux en faire.

un nombre flottant (float) est stocké sur 4 octets, un int sur 2 octets et un byte (ou uint8_t) sur 1 octet. Les float et les int sont signés, les byte/uint8_t non.

Tu étais parti sur une représentation sous forme de chaîne de caractères des différentes valeurs de tes capteurs. Tu aurais pu faire le choix de partir sur une copie des octets des entiers (les 2 octets qui servent à les mémoriser).

Exemple :

int v=1234; sera stocké en mémoire sous la forme de 2 octets : 4,210 (car 1234=4x256+210), et sera représenté par la chaîne de caractère "1234" (4 octets).

En choisissant d'émettre la chaine tu émets plus ou moins de caractères , cela dépends de la valeur de l'entier. En choisissant d'émettre la représentation interne des entiers tu émets 2 octets, quelque soit la valeur de l'entier.

Les 2 choix fonctionneront et ont leurs avantages et inconvénients.

avantage de la représentation chaîne de caractères : plus lisible pour l'homme (débogage), l'émetteur et le récepteur n'ont pas besoin de connaître la représentation interne utilisé par l'autre.

inconvénients : nécessite du CPU pour faire la conversion et le résultat à une longueur variable.

Perso j'ai une préférence pour les chaines car elle sont plus lisibles mais j'envoie souvent des entiers, des float, ou des tableaux ou des structures plus complexes sans passer par une représentation de chaines pour des raisons de performances.

Exemple 1 :

Je cherche à émettre un tableau d'entiers :

int t[4]={1022, 17762, -2543, 12};
...
LMIC_setTxData2(1, t, 4*sizeof(int), 0); 
...

Exemple 2 :

Dans le cas de l'émission d'un tableau de structures :

typedef struct {
  byte type;
  float value;
} Capteur

Capteur t[4] = { {0,3.2}, {0, -12.3}, {5, -12345.3}, {3, 42.0}};
...
LMIC_setTxData2(1, t, 4*sizeof(Capteur), 0); 
...

C'est plus simple que de passer par des chaînes de caractères par contre il faut que le receveur utilise la même représentation interne des types ou qu'il convertisse ce qu'il reçoit dans sa représentation interne.

En espérant que cela t'aide.

C’est super intéressant ce que tu m’explique et je crois que ceci

typedef struct {
  byte type;
  float value;
} Capteur

Capteur t[4] = { {0,3.2}, {0, -12.3}, {5, -12345.3}, {3, 42.0}};
...
LMIC_setTxData2(1, t, 4*sizeof(Capteur), 0);
...

ca m’être d’une énorme utilité car c’est exactement ce que je fais, mais je complique ensuite!!!
Il va me permettre de simplifier mon code!!! et surtout supprimer ‘payload’ que je suspecte.

Au passage, je crois avoir compris pourquoi je n’arrive pas à envoyer toutes les deux heures, mais je m’attarderai la dessus plus tard, pour ne pas trop charger mon post, mais ca marche maintenant suite à une modification :slight_smile:

Je m’explique, et je vais balancer du code :slight_smile:

D’abord, j’utilise aussi un truc pour stocker mes valeurs des capteurs. Initialement, c’était pour faire du debugage et pour afficher les capteurs actifs ou pas.

const byte capteur_temperature_id = 0;
  const byte capteur_pression_id = 1;
  const byte capteur_humidity_id = 2;
  const byte capteur_luminosity_id = 3;
  const byte capteur_wm1_id = 4;
  const byte capteur_wm2_id = 5;
  const byte capteur_wm3_id = 6;
  const byte capteur_datetime_id = 7;
  const byte capteur_temperature_soil_id = 8;
  const byte capteur_gauge_id = 9;
  const byte capteur_battery_id = 10;
  
  struct capteur
  {
    uint8_t idDuCapteur;
    boolean actif;
    const char * nomDuCapteur;
  }; 
  
  capteur mesCapteur[] = {
    {capteur_temperature_id, temperature_active, "te"},
    {capteur_pression_id, pression_active, "pr"},
    {capteur_humidity_id, humidity_active, "hu"},
    {capteur_luminosity_id, luminosity_active, "lu"},
    {capteur_wm1_id, wm1_active, "w1"},
    {capteur_wm2_id, wm2_active, "w2"},
    {capteur_wm3_id, wm3_active, "w3"},
    {capteur_datetime_id, datetime_active, "da"},
    {capteur_temperature_soil_id, temperature_soil_active, "ts"},
    {capteur_gauge_id, gauge_active, "ga"},
    {capteur_battery_id, battery_active, "ba"},
  };
  // dans le même ordre que mesCapteurs
  enum : byte {c_temperature=0, c_pression, c_humidity, c_luminosity, c_wm1, c_wm2, c_wm3, c_datetime, c_temperature_soil,c_gauge,c_battery};
  const byte nbMaxCapteurs = sizeof(mesCapteur) / sizeof(mesCapteur[0]);
  byte nbCapteurActif = 0;
  
  
  struct mesure {
    uint16_t id_capteur;
    //int valeur; // valeur mesurée (adapter le type)
    uint8_t valeur; // valeur mesurée (adapter le type)
    int var_size; // valeur mesurée (adapter le type)
    // autre chose de pertinent à mémoriser lors d'une mesure ?
  };
  
  const byte tailleHistorique = 11; // Ce chiffre doit correspondre aux nombres de capteurs. Voir capteur mesCapteur[] = {
  mesure mesMesures[nbMaxCapteurs][tailleHistorique];

On voit ici que j’utilise ce struct pour stocker mes valeurs

  struct mesure {
    uint16_t id_capteur;
    //int valeur; // valeur mesurée (adapter le type)
    uint8_t valeur; // valeur mesurée (adapter le type)
    int var_size; // valeur mesurée (adapter le type)
    // autre chose de pertinent à mémoriser lors d'une mesure ?
  };
  
  const byte tailleHistorique = 11; // Ce chiffre doit correspondre aux nombres de capteurs. Voir capteur mesCapteur[] = {
  mesure mesMesures[nbMaxCapteurs][tailleHistorique];

Je cois que tu connais la librairie arduino-lmic.
Dans ma fonction do_send(){}, je fais appelle à des fonction qui vont relever les mesures dont voici un exemple (je la simplifie qu’avec la température pour expliquer mon raisonnement que je vais immédiatement changer):

void get_baro(int &i_t) 
{
  float r_tem;
  i_t=0;

    //get and print temperatures
    Si.sprint(F("Temp: "),2);

      r_tem = bme.readTemperature();

    Si.sprint(r_tem,2);
    Si.sprint(F("C"),2);//The unit for  Celsius because original arduino don't support special symbols
    Si.sprint(F("\t"),2);
    i_t = (int)r_tem;
}

Je passe en paramètre itemp. La fonction va récupérer la température, qui la convertis en int

int itemp;
get_baro(itemp);
mesMesures[c_temperature][capteur_temperature_id].valeur = itemp;

puis je la sauve dans ma structure en char

Ouha!

Puis à la fin de do_send(), j’encapsule dans payload (ce code comprend tous mes capteur). Et c’est cette partie que je suspectait etre la cause de mon problème d’envoi, toutes les deux heures, qui apparemment ne l’est pas…

 //Si.sprintln(F("\r\nEmpilations des valeurs capteurs"), 2);
        //Si.sprintln(F("---------------------------------------"), 0);
         memset(payload,'\0',payloadSize);
        uint8_t * ptr = payload;

        for (byte i = 0; i < nbMaxCapteurs; i++) {
         // if (mesCapteur[i].actif) { 

            // PRINT LES MESURES MESUREES
            itoa(mesMesures[i][mesCapteur[i].idDuCapteur].valeur, (char *) ptr, 10); // on écrit à partir de ptr la représentation ASCII en base 10 de la valeur de ibatt
            ptr += strlen((char *) ptr);
        
            if (i < nbMaxCapteurs-1)
            {
              *ptr = ','; // virgule
              ptr += sizeof(char);
            }
            else
            {
              *ptr = ',' ; // Je ferme
            }
          /*
          }
          else // si le capteur n'est pas actif on n'imprime pas
          {
            if (i < nbMaxCapteurs-1)
            {
              *ptr = ','; // virgule
              ptr += sizeof(char);
            }
            else
            {
              *ptr = 0; // Je ferme. Pas bouger le pointeur
            }
          }
          */
        }

En fait, mon processus d’envoi se fait en 3 étapes, de passe d’une variable à une autre et de différent type.

Tu m’a montré qu’on pouvait envoyer un struct.

typedef struct {
  byte type;
  float value;
} Capteur

Capteur t[4] = { {0,3.2}, {0, -12.3}, {5, -12345.3}, {3, 42.0}};
...
LMIC_setTxData2(1, t, 4*sizeof(Capteur), 0);
...

C’est bien ca?

Donc pourquoi, je ne pourrais pas envoyer mon struct???

struct mesure {
    uint16_t id_capteur;
    //int valeur; // valeur mesurée (adapter le type)
    uint8_t valeur; // valeur mesurée (adapter le type)
    int var_size; // valeur mesurée (adapter le type)
    // autre chose de pertinent à mémoriser lors d'une mesure ?
  };
  
  const byte tailleHistorique = 11; // Ce chiffre doit correspondre aux nombres de capteurs. Voir capteur mesCapteur[] = {
  mesure mesMesures[nbMaxCapteurs][tailleHistorique];

Je verrai demain, comment adapter mon code en fonction de ton deuxième exemple!

Mais si c’est faisable, c’est génial, car je vais énormément optimiser mon code.

Par exemple, dans mon fonction get_baro:

 void get_baro()
 {
  float f_tem, f_pre, f_alt, f_hum;
  uint8_t u_tem, u_pre, u_alt, u_hum;
  #if defined(SENSOR_BME280_ADA)
    Si.sprintln(F("\r\nBarometric Pressure Sensor (BME280)"), 2);
    Si.sprintln(F("******************************"), 2);
  
    //get and print temperatures
    Si.sprint(F("Temp: "),2);
    f_tem = bme.readTemperature();
    Si.sprint(f_tem,2);
    Si.sprint(F("C"),2);//The unit for  Celsius because original arduino don't support speical symbols
    Si.sprint(F("\t"),2);
  
    u_tem = f_tem;
    Serial.println(u_tem);
    Serial.println(u_tem,DEC);
    mesMesures[c_temperature][capteur_temperature_id].valeur = u_tem;
}

Plus besoin de passer quoi se soit en paramètre et de les récupérer après l’exécution de la fonction get_baro()
et je supprime le “processus” d’empilation que je suspectais d’être la cause de mon problème initial

car j’envoie directement ma struct ‘mesMesures’

Est-ce que je vois juste ou je plane sur un nuage ? :slight_smile:

Par si je vois la bonne direction, j’applique ca demain. Je suis en train de refaire mon code dans un nouveau fichier,ce qui a l’avantage de bien le nettoyer :slight_smile: :slight_smile: :slight_smile: :slight_smile:

Oui tu as bien compris, on peut envoyer des struct et même un tableau de struct directement mais attention :

  • le récepteur devra être du même type endianness ou faire les conversion nécessaire à la réception.

  • Je ne connais pas la bibliothèque arduino-lmic et à peine les principes de LoRa mais c'est ici c'est très proche de ce que l'on fait aussi en UDP. Par contre méfie toi, le payload de LoRa à une taille assez limité je pense (cf. par exemple ici. C'est peut-être la cause de certains de tes problèmes.

D'ailleurs si tu stockes dans ton tableau de mesures les capteurs inactifs tu utilises des octets pour rien (en mémoire et dans ton payload). Je ne sais pas quelles sont tes contraintes mais j'éviterai de gérer des capteurs inactifs. A quel moment un capteur inactif devient actif et vice versa dans ton programme ?

Salut supercc

Merci pour tes observations

on peut envoyer des struct et même un tableau de struct directement

Mais est-ce que ca prendra plus deplace que ceci

35 38 32 2C 2C 2C 2C 2C 2C 2C 34 35 2C 2C 2C 30 2C 2C 2C 30 2C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

ou on ne perd rien en terme de taille de l'envoi?

Par contre méfie toi, le payload de LoRa à une taille assez limité je pense

En enffet, j'avais déjà vu la motion de 52 et je vais limité mon buffer à 52.

D'ailleurs si tu stockes dans ton tableau de mesures les capteurs inactifs tu utilises des octets pour rien

Ouine effet, mais je ne pense pas que je pourrai faire autrement car chez TTN, je récupère mes donnée ainsi

function Decoder(bytes, port) {
  var str=String.fromCharCode.apply(null,bytes);
  var astr = str.split(",");
  
  return{
    te:astr[0],
    pr:astr[1],
    al:astr[2],
    hu:astr[3],
    //mo:astr[5],
    lu:astr[4],
    w1:astr[5],
    w2:astr[6],.
    w3:astr[7],
    da:astr[8],
    //aq:astr[11],
    ts:astr[9],
    ga:astr[10],
    ba:astr[11],
    //wi:astr[14],
  };

Donc si je n'envoi pas les capteurs inactif, l'indexation change, et par exemple, lu n'aura plus la mêm indexation si al est inactif

D'ailleurs, as-tu une idée comment je peux récupérer un struct, alors? un struct est comme un array?
Si l'envoi d'un struct n'est plus gournent qu'un chaine de caratere, je pense que je vais aller dans cette diretcion.

Il faudra juste que je vérifie avant l'envoi que mon struct n'a pas plus de 52byte :slight_smile:

Merci

En fait, je suis arrivé à faire un truc de relativement intéressant.

Je construis un struct qu’avec les données actives et ca semble bien fonctionner. Si je pouvais encore avoir ta patience et tes lumières, j’apprécierais :slight_smile: .

Je déclare un struct de la manière suivante:

typedef struct {
  byte value;
}Payload;

Puis dans ma fonction do_send(), celle qui est appelée tous les x temps et qui va questionner mes capteurs, j’ai déjà ceci qui fonctionne et qui va afficher mes valeurs:

Si.sprintln(F("\r\n\r\nResults"), 2);
        Si.sprintln(F("******************************"), 2);
        Si.sprint(F("Nb sensors: "), 2);
        Si.sprintln(nbMaxCapteurs, 2);
        Si.sprint(F("Nb active sensors: "), 2);
        Si.sprintln(nbCapteurActif, 2);

        Si.sprint(F("Sensor values:\t"), 2);

        // Loop la strcture des capteurs
        Si.sprint(F("{"),2); 
        for (byte i = 0; i < nbMaxCapteurs; i++) {
          if (mesCapteur[i].actif) { 
            
            Si.sprint(mesCapteur[i].nomDuCapteur, 2);
            Si.sprint(F(":"), 2);
            Si.sprint(mesMesures[i][mesCapteur[i].idDuCapteur].valeur, 2);
            if (i < nbMaxCapteurs-1) Si.sprint(F(","), 2);
          
          }
          else
          {
            // Below, can be commented later 
            Si.sprint(mesCapteur[i].nomDuCapteur, 2);
            Si.sprint(F(":"), 2);
            Si.sprint(mesMesures[i][mesCapteur[i].idDuCapteur].valeur, 2);
            if (i < nbMaxCapteurs-1) Si.sprint(F(","), 2);
          }
        }
        Si.sprintln(F("}"),2);

Si je reprends ceci et je fais:

Payload p[nbCapteurActif];
for(int pp = 0; pp < nbMaxCapteurs; pp++)
        {
          if (mesCapteur[pp].actif)
          { 
            p[pp].value =  mesMesures[pp][mesCapteur[pp].idDuCapteur].valeur;
          }
        }

Puis je vérifie mon payload,

for(int qq=0; qq<nbCapteurActif; qq++)
        {
          Serial.println(p[qq].value );
        }

J’ai ceci:

27
201
52
20
0
43
0

C’est très intéressant, car j’ai bien mes 7 capteurs actifs.

Le problème que je vois est

  1. 201 devrait être 969
  2. 43 devrait être 329
  3. et les autres ne dont pas du genre: 32 37 pour 27, etc

Je pense que la raison, je mets un int dans un byte et vu qu’un byte à un octet et un int en a 2 octet (comme tu l’as écris plus haut, il doit buger à cause de ceci.

J’ai essayé ceci, mais sans succès

Payload p[nbCapteurActif];
for(int pp = 0; pp < nbMaxCapteurs; pp++)
        {
          if (mesCapteur[pp].actif)
          { 
            p[pp].value =  (byte)mesMesures[pp][mesCapteur[pp].idDuCapteur].valeur;
          }
        }

Est-ce que j’ose encore te demander un coup de main pour remplir mon payload de type struct en byte?

Pour vérifier sa taille afin de mettre une condition s’il était plus grand que 52 byte, je dois bien faire:

      int sp= sizeof(Payload);

        Si.sprint(F("Size of payload * nbCapteurActif: "),2);
        Si.sprintln(nbCapteurActif * sp,2);

Encore milles mercis pour ton suivi et aide!!!

D'ailleur, voici ce que je viens de lire dans la FAQ:

How many bytes can I send?

Technically, you can send 51 bytes. But, the more bytes you’ll send, the more airtime the package will cost you and the sooner you’ll hit your maximum allotted time. So, don’t ask yourself how many you can possibly send but rather ask how few could do the job.

Je me demande si ca peut aider, mais j'ai un peu d emal à comprendre :o

Salut Pierrot,

EDIT : ce que tu lis est ma réponse au premier post de la soirée, je vais regarder les 2 autres que tu as posté :wink:

la fonction javascript decode que tu présentes, c'est toi qui l'a écrit, tu es maître du code qu'elle contient n'est ce pas ?

Je réitère ma question du post précédent : A quel moment un capteur inactif devient actif et vice versa dans ton programme ?

Autre question : les valeurs que tu veux envoyer tiennent-elles toutes sur un même type de variable. Si oui lequel (int, unsigned int, ...). Si non quels sont les différentes types que tu veux utiliser ?

Si tu veux que je te donne des indications pas trop foireuses il faut que je me fasse une idée plus claire de ces points (et d'autres peut-être par la suite).

pierrot10:
Mais est-ce que ca prendra plus deplace que ceci

cela dépend des valeurs (cf post précédent) mais si tu envois directement des struct ou un tableau la taille sera connue et fixe alors qu'avec des chaînes de caractères cela peut dépasser le payload dans certains cas et pas dans d'autres ce qui complexifie l'émission.

pierrot10:
En enffet, j'avais déjà vu la motion de 52 et je vais limité mon buffer à 52.

D'après la doc c'est 51 max. Cette doc est intéressante, elle explique comment coder/décoder :wink:

un struct est comme un array?

Non, un tableau est un ensemble d'éléments forcément de même type. Une struct est un ensemble d'éléments de types éventuellement différents. Un tableau permet d'adresser les éléments à l'aide d'un indice. Une struct permet d'adresser ses éléments (on les appelle des champs) à l'aide de leur nom. Mais du point de vu de la transmission des infos c'est assez similaire au final : on donne l'adresse du début, la taille et zou c'est parti ;-), pas la peine de passer par des chaînes de caractères (modulo le problème "endianness" déjà évoqué plus haut mais pas insurmontable si tu traites les infos reçues en javascript).

A+

Salut supercc!!!!!!

Trop sympa :slight_smile:

la fonction javascript decode que tu présentes, c'est toi qui l'a écrit, tu es maître du code qu'elle contient n'est ce pas ?

Si tu parle de celle-ci, oui je suis maitre de ceci, il y a une inetrface pour la modifier chez TTN

function Decoder(bytes, port) {
  var str=String.fromCharCode.apply(null,bytes);
  var astr = str.split(",");
  
  return{
    te:astr[0],
    pr:astr[1],
    al:astr[2],
    hu:astr[3],
    //mo:astr[5],
    lu:astr[4],
    w1:astr[5],
    w2:astr[6],
    w3:astr[7],
    da:astr[8],
    //aq:astr[11],
    ts:astr[9],
    ga:astr[10],
    ba:astr[11],
    //wi:astr[14],
  };
}

Je réitère ma question du post précédent : A quel moment un capteur inactif devient actif et vice versa dans ton programme ?

C'est moi qui défini ceci. Un capteur l'est ou ne l'est pas. Il ne change pas d'état durant les mesures. Je peux avoir une station avec 4 capteurs et une autre avec 7 capteurs. etc.

Par contre, TTN récupère les données envoyées à la gateway et les index des capteurs doivent être les meme - Donc ceci

p[pp].value =  mesMesures[pp][mesCapteur[pp].idDuCapteur].valeur;

devra être remplacé par

p[mesCapteur[pp].idDuCapteur].value =  mesMesures[pp][mesCapteur[pp].idDuCapteur].valeur;

Si non,l'index changera en fonction du nombre de capteurs actif ou pas et ca ne seraplus gérable ducôté de TTN (javascript)

Non, un tableau est un ensemble d'éléments forcément de même type. Une struct est un ensemble d'éléments de types éventuellement différents.Un tableau permet d'adresser les éléments à l'aide d'un indice. Une struct permet d'adresser ses éléments (on les appelle des champs) à l'aide de leur nom

Oui,en effet!

:slight_smile:

Est-ce que mes réponses sont assez précises?

Tu as bien identifié le problème. Quand tu transformes un int en byte tu ne gardes que le poids faible.

Si tu veux des int (de -32768 à +32767) il va falloir émettre des int et donc :

typedef struct {
  int16_t value;
}Payload;

Tu n’auras plus qu’a envoyer ton tableau p (Payload p[nbCapteurActif]) de la façon suivante :

LMIC_setTxData2(1, p, sizeof(p), 0);

PS : la taille d’un int dépend de bus de données du processeur. Il est préférable d’utiliser le type int16_t pour un int sur 2 octets.

A la réception, dans le javascript, il faudra éventuellement remettre les 2 octets dans le bon ordre (problème endianness), mais c’est normalement assez trivial.