Parsing d'une trame TIC

Bonjour,

J’essai actuellement de récupérer les infos d’un port de télé-information client sur arduino. Pour l’instant, tout ce que j’arrive à faire (grâce à un tuto) c’est d’afficher sur le moniteur série arduino les caractères de ma trame grâce au code suivant :

#include <SoftwareSerial.h>
#define startFrame 0x02
#define endFrame 0x03

SoftwareSerial* cptSerial;

void setup()
{
  Serial.begin(115200);
  cptSerial = new SoftwareSerial(8, 9);
  cptSerial->begin(1200);
  Serial.println(F("setup complete"));
}

void loop()
{
  char charIn = 0;
  while (charIn != startFrame)
  {
    charIn = cptSerial->read() & 0x7F;
  }
  while (charIn != endFrame)
  {
    if (cptSerial->available())
    {
      charIn = cptSerial->read() & 0x7F;
      Serial.print(charIn);
    }
  }
  Serial.println("");
}

J’aimerais maintenant pouvoir “stocker” ces caractères dans un tableau de char pour pouvoir les traiter par la suite. Seulement je suis novice en arduino et j’ai essayé bien des choses mais sans succès. Si vous avez des suggestions ou des idées, je suis preneur.

Merci d’avance.

hello
voici un lien qui devrait t’interresserICI

un grand merci à MicroQuettas

Merci pour le lien, malheureusement j'ai déjà consulté ce topic et pour être honnête ça ne m'aide pas vraiment car le programme de MicroQuettas est assez complexe, donc difficile à comprendre pour quelqu'un qui, comme moi, débute. De plus MicroQuettas utilise des fichiers.h or je dois rester sur un fichier .ino.

Rester sur un .ino : qui t'impose une pareille contrainte ?

Par exemple, tu utilises SoftwareSerial. As-tu compris cette librairie ? As-tu seulement ouvert les sources ?
Probablement non. Mais cela ne t'empêche pas de l'utiliser sans comprendre.

Le .cpp et le .h de MicroQuettas peuvent s'installer comme n'importe quelle librairie ARDUINO.
Ensuite son .ino est très simple.
Il affiche Index base, Courant instantané, Puissance instantanée.

Salut ,
sinon , peut etre que ca fait ce que tu desires , mais je n’ ai pas pu testé .

#include <SoftwareSerial.h>
#define startFrame 0x02
#define endFrame 0x03

SoftwareSerial* cptSerial;
char tableauDeChar [ 100 ] = {}; // initialisation du tableau de char vide avec 100 caracteres possible

void setup()
{
  Serial.begin(115200);
  cptSerial = new SoftwareSerial(8, 9);
  cptSerial->begin(1200);
  Serial.println(F("setup complete"));
}

void recupEtAffiche_TIC () {
    
      char charIn = 0;
      uint8_t i = 0;
  while (charIn != startFrame)
  {
    charIn = cptSerial->read() & 0x7F;
  }
  while (charIn != endFrame)
  {
    if (cptSerial->available())
    {
        i++;
      charIn = cptSerial->read() & 0x7F;
      Serial.print(charIn);
      tableauDeChar[i] = charIn; // remplissage du tableau avec les caracteres recuperes
    }
  }
  Serial.println("");
}

void loop()
{
    recupEtAffiche_TIC (); // lance la fonction de recuperation des caracteres et les affiche .
}

@hbachetti, Si je dois rester seulement sur un .ino c'est pour respecter un cahier des charges. J'ai bien décortiquer et compris comment fonctionne la librairie SoftwareSerial, je te remercie de t'en soucier. Je ne "l'utilise donc pas sans comprendre". De plus le .ino ne m’intéresse pas dans le programme de MicroQuettas car le parsing des trames TIC est fait dans les .h que je ne comprends pas et que je ne peux donc pas exploiter. Merci pour ta réponse mais s'il te plait à l'avenir évites de suggérer que je n'ai pas compris le programme que j'utilise.

@iznobe, merci pour ton aide, pour vérifier si les caractères étaient bien stockés dans le tableau j’ai rajouté une boucle for qui affiche indice par indice les caractères du tableau, malheureusement on retombe sur le résultat que j’ai obtenue avant : aucun des caractères du tableau ne s’affiche dans la boucle for avec le programme suivant :

#include <SoftwareSerial.h>
#define startFrame 0x02
#define endFrame 0x03

SoftwareSerial* cptSerial;
char tableauDeChar [ 100 ] = {}; // initialisation du tableau de char vide avec 100 caracteres possible
char var;

void setup()
{
  Serial.begin(115200);
  cptSerial = new SoftwareSerial(8, 9);
  cptSerial->begin(1200);
  Serial.println(F("setup complete"));
}

void recupEtAffiche_TIC () {
   
      char charIn = 0;
      uint8_t i = 0;
  while (charIn != startFrame)
  {
    charIn = cptSerial->read() & 0x7F;
  }
  while (charIn != endFrame)
  {
    if (cptSerial->available())
    {
        i++;
      charIn = cptSerial->read() & 0x7F;
      Serial.print(charIn);
      tableauDeChar[i] = charIn; // remplissage du tableau avec les caracteres recuperes
      
    }
  }
  Serial.println("");
}

void loop()
{
    recupEtAffiche_TIC (); // lance la fonction de recuperation des caracteres et les affiche .
    for(int i=0; i<100; i++)
    {
      Serial.print(tableauDeChar[i]);
    }
}

Une idée ?

De plus le .ino ne m'intéresse pas dans le programme de MicroQuettas car le parsing des trames TIC est fait dans les .h que je ne comprends pas

Le parsing de MicroQuettas est fait dans le .cpp.

Et son code est d'une infinie simplicité par rapport à celui de SoftwareSerial.

Je ne pense pas que tu saches de quoi tu parles.
Un peu de modestie ne fait pas de mal.

De plus on n'a jamais empêché qui que ce soit d'intégrer le contenu d'un .h et d'un .cpp dans un .ino pour n'en faire qu'un seul fichier, bien que ce ne soit pas la manière la plus intelligente de travailler.

Ceci dit, bonne suite.

@hbachetti Comme je l’ai déjà précisé je suis débutant et désolé mais je ne trouve pas ça :

/***********************************************************************
               Objet decodeur de teleinformation client (TIC)
               format Linky "historique" ou anciens compteurs
               electroniques.

Lit les trames et decode les groupes :
  BASE  : (base) index general compteur en Wh,
  IINST : (iinst) intensit� instantan�e en A,
  PAPP  : (papp) puissance apparente en VA.

Reference : ERDF-NOI-CPT_54E V1

V06 : MicroQuettas mars 2018

***********************************************************************/

/***************************** Includes *******************************/
#include <string.h>
//#include <Streaming.h>
#include "LinkyHistTIC.h"

#define LINKYDEBUG true

/***********************************************************************
                  Objet r�cepteur TIC Linky historique

 Trame historique :
  - d�limiteurs de trame :     <STX> trame <ETX>
    <STX> = 0x02
    <ETX> = 0x03

  - groupes dans une trame : <LF>lmnopqrs<SP>123456789012<SP>C<CR>
    <LR> = 0x0A
    lmnopqrs = label 8 char max
    <SP> = 0x20 ou 0x09 (<HT>)
    123456789012 = data 12 char max
    C = checksum 1 char
    <CR> = 0x0d
       Longueur max : label + data = 7 + 9 = 16

  _FR : flag register
.
.
.
.
      case CLy_base:
        ba = atol(_pDec);
        if (_base != ba)
          {  /* New value for _base */
          _base = ba;
          SetBits(_DNFR, bLy_base);
          }
        break;

      case CLy_iinst:
        i = (uint8_t) atoi(_pDec);
        if (_iinst != i)
          {  /* New value for _iinst */
          _iinst = i;
          SetBits(_DNFR, bLy_iinst);
          }
        break;

      case CLy_papp:
        pa = atoi(_pDec);
        if (_papp != pa)
          {  /* New value for papp */
          _papp = pa;
          SetBits(_DNFR, bLy_papp);
          }
        break;

      default:
        break;
      }
    }

  /* 2nd part, second action : group identification */
  if (_FR & bLy_GId)
    {
    ResetBits(_FR, bLy_GId);   /* Clear requesting flag */
    _pDec = strtok(_pDec, CLy_Sep);

    if (strcmp_P(_pDec, PLy_base) == 0)
      {
      Run = false;
      _GId = CLy_base;
      }

    if (Run && (strcmp_P(_pDec, PLy_iinst) == 0))
      {
      Run = false;
      _GId = CLy_iinst;
      }

    if (Run && (strcmp_P(_pDec, PLy_papp) == 0))
      {
      Run = false;
      _GId = CLy_papp;
      }

    if (!Run)
      {
      SetBits(_FR, bLy_Dec);   /* Next = decode */
      }
    }

  /* 3rd part, first action : check cks */
  if (_FR & bLy_Cks)
    {
    ResetBits(_FR, bLy_Cks);   /* Clear requesting flag */
    cks = 0;
    if (_iCks >= CLy_MinLg)
      {   /* Message is long enough */
      for (i = 0; i < _iCks - 1; i++)
        {
        cks += *(_pDec + i);
        }
      cks = (cks & 0x3f) + Car_SP;

      #ifdef LINKYDEBUG
      Serial << _pDec << endl;
      #endif

      if (cks == *(_pDec + _iCks))
        {  /* Cks is correct */
        *(_pDec + _iCks-1) = '\0';
                       /* Terminate the string just before the Cks */
        SetBits(_FR, bLy_GId);  /* Next step, group identification */

        #ifdef LINKYDEBUG
        }
        else
        {
        i = *(_pDec + _iCks);
        Serial << F("Error Cks ") << cks << F(" - ") << i << endl;
        #endif
        }   /* Else, Cks error, do nothing */

      }     /* Message too short, do nothing */
    }

  /* 4th part, receiver processing */
  while (_LRx.available())
    {  /* At least 1 char has been received */
    c = _LRx.read() & 0x7f;   /* Read char, exclude parity */

    if (_FR & bLy_Rec)
      {  /* On going reception */
      if (c == '\r')
        {   /* Received end of group char */
        ResetBits(_FR, bLy_Rec);   /* Receiving complete */
        SetBits(_FR, bLy_Cks);     /* Next check Cks */
        _iCks = _iRec-1;           /* Index of Cks in the message */
        *(_pRec + _iRec) = '\0';   /* Terminate the string */

        /* Swap reception and decode buffers */
        if (_FR & bLy_RxB)
          {  /* Receiving in B, Decode in A, swap */
          ResetBits(_FR, bLy_RxB);
          _pRec = _BfA;       /* --> Receive in A */
          _pDec = _BfB;       /* --> Decode in B */
          }
          else
          {  /* Receiving in A, Decode in B, swap */
          SetBits(_FR, bLy_RxB);
          _pRec = _BfB;     /* --> Receive in B */
          _pDec = _BfA;     /* --> Decode in A */
          }

        }  /* End reception complete */
        else
        {  /* Other character */
        *(_pRec+_iRec) = c;   /* Store received character */
        _iRec += 1;
        if (_iRec >= CLy_BfSz-1)
          {  /* Buffer overrun */
          ResetBits(_FR, bLy_Rec); /* Stop reception and do nothing */
          }
        }  /* End other character than '\r' */
      }    /* End on-going reception */
      else
      {    /* Reception not yet started */
      if (c == '\n')
        {   /* Received start of group char */
        _iRec = 0;
        SetBits(_FR, bLy_Rec);   /* Start reception */
        }
      }
    }  /* End while */
  }


bool LinkyHistTIC::baseIsNew()
  {
  bool Res = false;

  if(_DNFR & bLy_base)
    {
    Res = true;
    ResetBits(_DNFR, bLy_base);
    }
  return Res;
  }

bool LinkyHistTIC::iinstIsNew()
  {
  bool Res = false;

  if(_DNFR & bLy_iinst)
    {
    Res = true;
    ResetBits(_DNFR, bLy_iinst);
    }
  return Res;
  }

bool LinkyHistTIC::pappIsNew()
  {
  bool Res = false;

  if(_DNFR & bLy_papp)
    {
    Res = true;
    ResetBits(_DNFR, bLy_papp);
    }
  return Res;
  }

uint32_t LinkyHistTIC::base()
  {
  return _base;
  }

uint8_t LinkyHistTIC::iinst()
  {
  return _iinst;
  }

uint16_t LinkyHistTIC::papp()
  {
  return _papp;
  }

/***********************************************************************
               Fin d'objet r�cepteur TIC Linky historique
***********************************************************************/

d’une “infinie simplicité”, même après 1h à essayer de comprendre le fonctionnement.

Crois bien une chose : personne ne se sent motivé, en tous cas pas moi, pour refaire ce qui a été fait par quelqu'un d'autre simplement parce qu'un débutant ne comprend pas le code.

L'interface du module de MicroQuettas est très simple à comprendre (voir LinkyHistTIC.h) :

    void Init();        /* Initialisation, call from setup() */
    void Update();      /* Update, call from loop() */

    bool baseIsNew();   /* Returns true if base has changed */
    bool iinstIsNew();  /* Returns true if iinst has changed */
    bool pappIsNew();   /* Returns true if papp has changed */

    uint32_t base();    /* Returns base index in Wh */
    uint8_t iinst();    /* Returns iinst in A */
    uint16_t papp();    /* Returns papp in VA */

Son .ino est suffisamment clair.

Autre solution, tu apprends à te servir de strtok(), strcmp(), etc. et tu fais le boulot toi-même.

@hbachetti, Le truc, c'est que dès le départ je ne demande pas une solution déjà toute faite comme tu me l'a apportée, je cherche à mettre en place par moi-même moyennant quelques idées et en précisant que je suis novice une solution à mon problème.

C'est gentil de ta part de me diriger vers un autre post mais il ne devrait pas y avoir de débat à partir du moment ou j'ai précisé que je ne comprenais pas le code et que l'objectif c'était justement que je comprenne ce que je fais.

"Crois bien une chose : personne ne se sent motivé, en tous cas pas moi, pour refaire ce qui a été fait par quelqu'un d'autre simplement parce qu'un débutant ne comprend pas le code." Ne te sens alors surtout pas obligé de répondre, tu n'es pas otage de ce post, et si tu n'est pas motivé alors passe juste ton tour.

elkilleros:
@iznobe, merci pour ton aide, pour vérifier si les caractères étaient bien stockés dans le tableau j'ai rajouté une boucle for qui affiche indice par indice les caractères du tableau, malheureusement on retombe sur le résultat que j'ai obtenue avant : aucun des caractères du tableau ne s'affiche dans la boucle for avec le programme suivant :

Une idée ?

la boucle est inutile , la fonction que j ' ai ajouté est identique a ton code de depart , elle est deja censé affiché les caracteres non ?

essaie de remplacer :

char tableauDeChar [ 100 ] = {}; // initialisation du tableau de char vide avec 100 caracteres possible

par

char *tableauDeChar [ 100 ] = {}; // initialisation du tableau de char vide avec 100 caracteres possible

@iznobe, Le but était de vérifier si les caractères s'enregistrait bien dans le tableau en question, et de les afficher justement en lisant le tableau. Et il s'avère que quand je lis le tableau avec la boucle for, rien ne s'affiche. En fait pour pouvoir traiter les informations j'aimerais pouvoir les manipuler via un tableau pour en extraire par la suite certain segment mais pour cela il faut que je sois sûr que les caractères s'enregistres bien dans le tableau dans le bon ordre, et quand quand je fasse par exemple un Serial.print(tabDeChar[9] (au hasard) le caractère "A" apparaisse sur le moniteur série.

Voilà je sais pas trop si c'est clair, merci pour ta réponse.

elkilleros:
@iznobe, Le but était de vérifier si les caractères s'enregistrait bien dans le tableau en question, et de les afficher justement en lisant le tableau. Et il s'avère que quand je lis le tableau avec la boucle for, rien ne s'affiche. En fait pour pouvoir traiter les informations j'aimerais pouvoir les manipuler via un tableau pour en extraire par la suite certain segment mais pour cela il faut que je sois sûr que les caractères s'enregistres bien dans le tableau dans le bon ordre, et quand quand je fasse par exemple un Serial.print(tabDeChar[9] (au hasard) le caractère "A" apparaisse sur le moniteur série.

Voilà je sais pas trop si c'est clair, merci pour ta réponse.

Si si , c ' est tres clair , essai de faire le changement dans mon post precedent pour voir , je ne peux pas tester ( je suis au taff et je n ' ai pas d' arduino sous la main ) .

par rapport a ton code de base , j ' ai ajouté le tableau de char en ligne 6 , puis je le remplis avec la ligne :

tableauDeChar[i] = charIn; // remplissage du tableau avec les caracteres recuperes

ton code n ' affiche rien sur le moniteur serie reglé a 115200 ?
si non , affiche t il avec le code que tu as founi au depart ?

elkilleros:
@hbachetti, Si je dois rester seulement sur un .ino c'est pour respecter un cahier des charges.

@iznobe : il est bien évident que tu as compris qu'il s'agit d'un travail d'étudiant ?

@iznobe, la trame apparaît bien sur le moniteur série grâce au code de base, mais lorsque je commente la ligne

recupEtAffiche_TIC ()

et qu’à la place je viens lire le tableau de char avec un for :

for(int i=0; i<100; i++)
    {
      Serial.print(tableauDeChar[i]);
    }

rien n’apparaît sur le moniteur série réglé à 115200 baud

Bonjour,

Affiches ton tableau sous forme de nombre pour voir s'il est rempli de 0

      Serial.print((int)tableauDeChar[i]);

@kamill Bonjour, en effet il semblerait que le tableau soit rempli de 0, je n'ai que ça sur le moniteur série avec cette commande.