Bonjour,

j’écris un code pour arduino. J'ai un problème avec une class template. J'immagine que j'ai oublié quelque chose dans l'écriture de ma class template, mais je sèche depuis hier... Pouvez vous jeter un coup d’œil pour m'aider?
Merci beaucoup!

le message d'erreur:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
[Tue Aug 30 16:01:17 2016] Processing megaatmega2560 (platform: atmelavr, board: megaatmega2560, framework: arduino)
--------------------------------------------------------------------------------
avr-g++ -o .pioenvs/megaatmega2560/src/main.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega2560 -DF_CPU=16000000L -DPLATFORMIO=021102 -DARDUINO_ARCH_AVR -DARDUINO_AVR_MEGA2560 -DARDUINO=10608 -I.pioenvs/megaatmega2560/FrameworkArduino -I.pioenvs/megaatmega2560/FrameworkArduinoVariant -I.pioenvs/megaatmega2560/Broches -I .pioenvs/megaatmega2560/SPI -I.pioenvs/megaatmega2560/PrintPGM -I.pioenvs/megaatmega2560/Adafruit_GFX_v1.0.2_NB8bits -I.pioenvs/megaatmega2560/PCD8544 -I.pioenvs/megaatmega2560/Clavier -I.pioenvs/megaatmega2560/IO_PCD8544_3touches -I.pioenvs/megaatmega2560/Widgets -Isrc src/main.cpp
avr-g++ -o .pioenvs/megaatmega2560/firmware.elf -Os -mmcu=atmega2560 -Wl,--gc-sections,--relax .pioenvs/megaatmega2560/src/main.o -L/hom/thom/.platformio/packages/ldscripts -L.pioenvs/megaatmega2560 -Wl,--start-group .pioenvs/megaatmega2560/libFrameworkArduinoVariant.a .pioenvs/megaatmega2560/libFrameworkArduino.a -lm .pioenvs/megaatmega2560/libBroches.a .pioenvs/megaatmega2560/libSPI.a .pioenvs/megaatmega2560/libPrintPGM.a .pioenvs/megaatmega2560/libAdafruit_GFX_v1.0.2_NB8bits .pioenvs/megaatmega2560/libPCD8544.a .pioenvs/megaatmega2560/libClavier.a .pioenvs/megaatmega2560/libIO_PCD8544_3touches.a .pioenvs/megaatmega2560/libWidgets.a -Wl,--end-group
.pioenvs/megaatmega2560/src/main.o: In function `loop':
/home/thom/Arduino/test_GFX/src/main.cpp:27: undefined reference to `Widgets<IO_PCD8544_3touches_SPI_software>::menuListeOuiNon(unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)'
.pioenvs/megaatmega2560/src/main.o: In function `__static_initialization_and_destruction_0':
/home/thom/Arduino/test_GFX/src/main.cpp:7: undefined reference to `Widgets<IO_PCD8544_3touches_SPI_software>::Widgets(IO_PCD8544_3touches_SPI_software&)'
collect2: error: ld returned 1 exit status
scons: *** [.pioenvs/megaatmega2560/firmware.elf] Error 1
le code du fichier main.cpp:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
26
27
28
29
30
#include <Arduino.h>
#include <IO_PCD8544_3touches.h>
#include <Widgets.h>

IO_PCD8544_3touches_SPI_software display=IO_PCD8544_3touches_SPI_software(BROCHE_ECRAN_SCLK, BROCHE_ECRAN_SDIN, BROCHE_ECRAN_DC, BROCHE_ECRAN_CS, BROCHE_ECRAN_RESET); // Software SPI (slower updates, more flexible pin options):

Widgets<IO_PCD8544_3touches_SPI_software> widgets(display);

void setup(){
    display.begin();
    display.setContrast(50);
    display.display();
    display.setTextColor(BLACK, WHITE);
    display.setTextSize(1);
}

void loop(){
  uint8_t touche;
  display.aucuneTouche();

  touche=display.getTouche(-1);
  display.println(millis());
  display.print(touche,BIN);
  display.display();
  display.aucuneTouche();

  widgets.menuListeOuiNon();
  display.clearDisplay();
}
le code du header de la librairie concernée: (Widgets.h)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
#ifndef __WIDGETS_H__
#define __WIDGETS_H__
 
#include <IO_PCD8544_3touches.h>
struct retourSelect {
  uint8_t touche;
  uint8_t result;
};
 
template<typename T>
class Widgets{
public:
  //Widgets();
  Widgets(T& _display);
 
  retourSelect menuListe(char* chaine, uint8_t nb, uint8_t taille = 15, uint8_t yMin = 0, uint8_t yMax = LCDHEIGHT, uint8_t xMin = 0, uint8_t xMax = LCDWIDTH, uint8_t hLigne = 1, uint8_t depart = 0, uint8_t textSize = 1, uint8_t actual = 0, uint8_t permissions = 0b10010000); // pour compatibilité avec l'ancienne forme
  retourSelect menuListeV2(void (*callback)(uint8_t, char*, uint8_t, void*), void* arg, uint8_t nb, uint8_t taille = 15, uint8_t yMin = 0, uint8_t yMax = LCDHEIGHT, uint8_t xMin = 0, uint8_t xMax = LCDWIDTH, uint8_t hLigne = 1, uint8_t depart = 0, uint8_t textSize = 1, uint8_t actual = 0, uint8_t permissions = 0b10010000);
  retourSelect menuListeOuiNon(uint8_t yMin = 0, uint8_t yMax = LCDHEIGHT, uint8_t xMin = 0, uint8_t xMax = LCDWIDTH, uint8_t hLigne = 1, uint8_t depart = 0, uint8_t textSize = 1, uint8_t permissions = 0b10010000);
protected:
  T* display;
};
 
void _creeLigneMenuListeV1(uint8_t i, char* chaine, uint8_t taille, void* arg);
void _creeLigneMenuListeOuiNon(uint8_t i, char* chaine, uint8_t taille, void* arg);
#endif
et le code de la librairie (Widgets.cpp):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include "Widgets.h"

template<typename T>
Widgets<T>::Widgets(T& _display){
  display=&_display;
}

template<typename T>
retourSelect Widgets<T>::menuListeOuiNon(uint8_t yMin, uint8_t yMax, uint8_t xMin, uint8_t xMax, uint8_t hLigne, uint8_t depart, uint8_t textSize, uint8_t permissions) {
  return menuListeV2(display, _creeLigneMenuListeOuiNon, (void*)&yMin, 2, 4, yMin, yMax, xMin, xMax, hLigne, depart, textSize, 0, permissions);
}

template<typename T>
retourSelect Widgets<T>::menuListe(char* chaine, uint8_t nb, uint8_t taille, uint8_t yMin, uint8_t yMax, uint8_t xMin, uint8_t xMax, uint8_t hLigne, uint8_t depart, uint8_t textSize, uint8_t actual, uint8_t permissions) {
  /*   affiche une liste est retourne le numéro de l'item selectionné
        liste est un tableau de pointeur vers des chaine comprenant la chaine de caractère de l'item
        nb est le nombre d'élément dans la liste principale
        taille donne la taille des élements de la chaine /!\ y compris le bit de fin de chaine /!\
        yMin est le point de départ de la liste en graphique (par défaut 0)
        yMax est le bas de la liste (par défaut bas de l'écran)
        xMin ... idem en X
        xMax ... idem en X
        hLigne est la hauteur de la ligne en nb de caractère (càd 1 car = 8 pixels de haut), par defaut 1
        permissions indique les permissions pour quitter le menu (autre que sélection), par défaut TIMEOUT & BT_ESC

        /!\ si plusieurs lignes pour une chaine (càd hLigne!=0) compter un caractère en plus pour chaque ligne pour ajouter une fin de ligne
  */

  return menuListeV2(display, _creeLigneMenuListeV1, (void*)chaine, nb, taille, yMin, yMax, xMin, xMax, hLigne, depart, textSize, actual, permissions);
}

template<typename T>
retourSelect Widgets<T>::menuListeV2( void (*callback)(uint8_t, char*, uint8_t, void*), void* arg, uint8_t nb, uint8_t taille, uint8_t yMin, uint8_t yMax, uint8_t xMin, uint8_t xMax, uint8_t hLigne, uint8_t depart, uint8_t textSize, uint8_t actual, uint8_t permissions) {
  /*   affiche une liste est retourne le numéro de l'item selectionné
        liste est un tableau de pointeur vers des chaine comprenant la chaine de caractère de l'item
        nb est le nombre d'élément dans la liste principale
        taille donne la taille des élements de la chaine /!\ y compris le bit de fin de chaine /!\
        yMin est le point de départ de la liste en graphique (par défaut 0)
        yMax est le bas de la liste (par défaut bas de l'écran)
        xMin ... idem en X
        xMax ... idem en X
        hLigne est la hauteur de la ligne en nb de caractère (càd 1 car = 8 pixels de haut), par defaut 1
        permissions indique les permissions pour quitter le menu (autre que sélection), par défaut TIMEOUT & BT_ESC

        /!\ si plusieurs lignes pour une chaine (càd hLigne!=0) compter un caractère en plus pour chaque ligne pour ajouter une fin de ligne
  */
#ifdef DEBUG
  Serial.print("menuListeV2(callback@");
  Serial.print((uint16_t)callback, HEX);
  Serial.print(", arg@");
  Serial.print((uint16_t)arg, HEX);
  Serial.print(", nb=");
  Serial.print(nb);
  Serial.print(", taille=");
  Serial.print(taille);
  Serial.print(", yMin=");
  Serial.print(yMin);
  Serial.print(", yMax=");
  Serial.print(yMax);
  Serial.print(", xMin=");
  Serial.print(xMin);
  Serial.print(", xMax=");
  Serial.print(xMax);
  Serial.print(", hLigne=");
  Serial.print(hLigne);
  Serial.print(", depart=");
  Serial.print(depart);
  Serial.print(", textSize=");
  Serial.print(textSize);
  Serial.print(", actual=");
  Serial.print(actual);
  Serial.print(", permissions=0b");
  Serial.print(permissions, BIN);
  Serial.println(");");
#endif

  //uint8_t tailleLigne;
  uint8_t largCarac = (textSize == 0) ? 4 : (6 * textSize);
  uint8_t hautCarac = (textSize == 0) ? 6 : (8 * textSize);

  taille = min(taille, ((xMax - xMin)  / largCarac + 1) * hLigne); // taille de la ligne en caractères
  //if (hLigne == 1)tailleLigne = taille;
  //else tailleLigne = (xMax - xMin) / largCarac + 1;
#ifdef DEBUG
  Serial.print("taille:");
  Serial.print(taille);
#endif

  uint8_t touche, pos, deb;
  uint8_t nbLigneVisible = min(((yMax - yMin) / (hautCarac * hLigne) ), nb); // nombre de ligne visible à la fois
  uint8_t derniereLigne = (((yMax - yMin) % (hautCarac * hLigne)  == 0) || (nb == nbLigneVisible)) ? 0 : 1;
  permissions &= 0b11110000; // pas de permissions pour les 4 1ere touche ( BT_SELECT,BT_HAUT,BT_BAS)
  uint16_t colorT = BLACK, colorF = WHITE;
  char chaine[22];


  // ajout depart
  if (depart == 0) {
    pos = 0;
    deb = depart;
  } else if ( depart <= nb - nbLigneVisible) {
    pos = 1;
    deb = depart - 1;
  } else {
    deb = nb - nbLigneVisible;
    pos = depart - deb;
  }
  display->setTextSize(textSize);
  for (;;) { // boucle infini complète
    // efface la zone d'affichage
    display->fillRect(xMin, yMin, xMax, yMax, WHITE);
    for (uint8_t i = 0; i < (nbLigneVisible + derniereLigne); ++i) {

      display->callback(i + deb, chaine, taille, arg);

      for (uint8_t j = 0; j < hLigne; ++j) {
        display->setCursor(xMin, yMin + (i * hLigne + j) * hautCarac);
        uint8_t hexa = 0;
        for ( uint8_t k = 0; k < taille && k < 22; ++k) {
          char c = chaine[k];
          if ( c == 0 && hexa == 0) break;
          if ( c == -1) {
            ++k;
            hexa = chaine[k];
          } else {
            if ( hexa != 0) {
              if ( (uint8_t)c < 16) display->print(0);
              display->print((uint8_t)c, HEX);
              --hexa;
            } else {
              display->print(c);
            }
          }
        }
      }
    }
    display->invertRect(xMin, yMin + (pos * hLigne) * hautCarac, xMax - xMin, hLigne * hautCarac);

    if (deb + nbLigneVisible == nb) display->fillRect(xMin, yMin + nbLigneVisible * hautCarac * hLigne, largCarac * (taille - 1), yMax - yMin - nbLigneVisible * hautCarac * hLigne, colorF);
    display->display();
    for (;;) { // boucle infini gestion touche
      display->aucuneTouche();
      if ( actual == 0) touche = display->getTouche(-1); // cas normal, pas d'actualisation
      else {
        touche = display->getTouche(actual);
        if ( touche == TIMEOUT  && millis() - display->getDateDerniereTouche() < 60000 ) {
          touche = 0; // si TIMEOUT mais qu'on n'a pas atteint l'extinction de l'ecran -> touche = 0
          break;
        }
      }
      if ( ((touche == TIMEOUT) && ((permissions & TIMEOUT) != 0)) || ((touche == (BT_HAUT | BT_BAS)) && ((permissions & BT_ESC) != 0)) || ((touche == (BT_HAUT | BT_BAS | BT_SELECT)) && ((permissions & BT_MENU) != 0)) || (touche == BT_SELECT)) break;

      if (touche == BT_BAS || touche == BT_HAUT) {
        display->invertRect(xMin, yMin + (pos * hLigne) * hautCarac, xMax - xMin, hLigne * hautCarac);
        if (touche == BT_BAS) {
          if ((pos == nbLigneVisible - 1) || (((deb + nbLigneVisible) != nb) && pos == nbLigneVisible - 2)) break;
          ++pos;
        } else { // touche == BT_HAUT
          if  ((pos == 0) || ((deb != 0 && pos == 1))) break;
          --pos;
        }
        display->invertRect(xMin, yMin + (pos * hLigne) * hautCarac, xMax - xMin, hLigne * hautCarac);
        display->display();
      }
    } // fin boucle infini gestion touche
    if ( touche != 0) {
      if (touche != BT_BAS && touche != BT_HAUT) break;
      if (touche == BT_BAS) {
        if (pos == nbLigneVisible - 1) {
          pos = 0;
          deb = 0;
        } else ++deb;
      } else { // touche BT_HAUT
        if (pos == 0) {
          pos = nbLigneVisible - 1;
          deb = (nbLigneVisible < nb) ? nb - nbLigneVisible : 0;
        }
        else --deb;
      }
    }
  } // fin boucle infinie complète
  if (touche == 0) touche = TIMEOUT;
  if (touche == BT_SELECT) touche = 0;
  display->invertRect(xMin, yMin + (pos * hLigne) * hautCarac, xMax - xMin, hLigne * hautCarac);
  display->display();

  retourSelect result;
  result.result = pos + deb;
  result.touche = touche;
  display->setTextSize(1);
  return result;
}

void _creeLigneMenuListeV1(uint8_t i, char* chaine, uint8_t taille, void* arg) {
  char* chaineCom = (char*)arg;
  strcpy(chaine, &chaineCom[i * taille]);
  return;
}

void _creeLigneMenuListeOuiNon(uint8_t i, char* chaine, uint8_t taille, void* arg) {
  switch (i) {
    case 0:
      //strcpy_P(chaine, TXT_OUI);
      strcpy(chaine,"OUI");
      break;
    case 1:
      //strcpy_P(chaine, TXT_NON);
      strcpy(chaine,"NON");
      break;
    default:
      break;
  }
}

//template<typename T>
//Widgets<T>::Widgets(){
//  display=NULL;
//}