Je viens chercher un peu d'aide car cette fois ci je me pose pas mal de questions.
J'ai un sketch qui tourne sur un arduino Mega2560 avec le quel je dialogue sur le port serie via les fonctions serial. Donc j'ai plein de serial.read() et serial.print() partout dans le code et tout fonctionne très bien.
Maintenant, je souhaite également faire tourner ce sketch sur un esp8266. tout fonctionne egalement et je dialogue via le port serie.
Ce que je souhaiterai faire c'est sur l'ESP8266 utiliser également le wifi (en plus du serial), mais sans devoir tout reécrire, c'est à dire sans devoir remplacer/ajouter à tous les serial.read() et les serials.print() des serverClients.read() et des serverClients.print().
Pensez-vous qu'il est possible de tromper les fonctions serial.x lorsque j'ai une variable global d'activé (WIFI=Y par exemple) pour que le serial.print() apppel en fait un serverClients.print() puis un serial.print() ?
Une possibilité serait de remplacer les Serial.print(), soit par des #define, soit des blocs #ifdef WIFI #else#fi dans lesquels tu écris soit des Serial.print() ou serverClient.print()
Une dernière possibilité : si Serial et ServerClient héritent de la même interface : instancier une référence de ce type, et l'assigner soit à Serial, soit ServerClient.
La dernière option est la suivante : SI (et seulement si) les classes définissant Serial et ton client dérivent de la même classe parent, et SI cette classe définit print() et println(), tu définis une variable globale en début de code comme une référence à cette classe "interface", et tu l'assignes à serial ou webclient.
C'est le principe du polymorphisme en POO.
Je rencontre un petit problème pour la fonction write. Voilà un code simplifié pour l'exemple :
#include <ESP8266WiFi.h>
#define MAX_SRV_CLIENTS 2 //how many clients should be able to telnet to this ESP8266
const char* ssid = "**********"; // Your SSID
const char* password = "**********"; // Your Wifi Key
WiFiServer server(23); //telnet port
WiFiClient serverClients[MAX_SRV_CLIENTS]; // Manage wifi client sessions in an array
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("\nConnecting to "); Serial.println(ssid);
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
if(i == 21){
Serial.print("Could not connect to"); Serial.println(ssid);
while(1) delay(500);
}
server.begin();
server.setNoDelay(true);
Serial.print("Ready! Use 'telnet ");
Serial.print(WiFi.localIP());
Serial.println(" 23' to connect");
}
void Notify_write ( char val ) {
Serial.write(val);
#if defined (ESP8266)
uint8_t i;
for(i = 0; i < MAX_SRV_CLIENTS; i++){
if (serverClients[i] && serverClients[i].connected()){
serverClients[i].write(val);
delay(1);
}
}
#endif
}
void loop() {
// put your main code here, to run repeatedly:
Notify_write('.');
}
ça ne compile pas
Voilà les erreurs :
Utilisation de la bibliothèque ESP8266WiFi prise dans le dossier : C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi
Utilisation de la bibliothèque ESP8266httpUpdate prise dans le dossier : C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266httpUpdate
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2/bin/xtensa-lx106-elf-g++ -D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ -IC:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f/tools/sdk//include -c -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -DF_CPU=80000000L -DARDUINO=10605 -DARDUINO_ESP8266_ESP12 -DARDUINO_ARCH_ESP8266 -DESP8266 -IC:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\cores\esp8266 -IC:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\variants\nodemcu -IC:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src -IC:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266httpUpdate\src C:\Users\xxx\AppData\Local\Temp\build4845589201134082340.tmp\test.cpp -o C:\Users\xxx\AppData\Local\Temp\build4845589201134082340.tmp\test.cpp.o
In file included from C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/ESP8266WiFi.h:32:0,
from test.ino:1:
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h: In instantiation of 'size_t WiFiClient::write(T&) [with T = char; size_t = unsigned int]':
test.ino:35:35: required from here
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:78:28: error: request for member 'available' in 'src', which is of non-class type 'char'
while (src.available() > WIFICLIENT_MAX_PACKET_SIZE){
^
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:79:7: error: request for member 'read' in 'src', which is of non-class type 'char'
src.read(obuf, WIFICLIENT_MAX_PACKET_SIZE);
^
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:87:38: error: request for member 'available' in 'src', which is of non-class type 'char'
uint16_t leftLen = src.available();
^
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:88:5: error: request for member 'read' in 'src', which is of non-class type 'char'
src.read(obuf, leftLen);
^
Erreur lors de la compilation.
Si je commente la ligne serverClients*.write(val); la compilation passe sans problèmes.* Un petit coup de main ne serait pas de refus edit: anonymisation du log d'erreur
Exact, je viens d'ajouter le pointeur et j'ai désormais une autre erreur. J'ai l'impression que le compileur s'attends a avoir un char et non un char* . j'avoue que je ne comprends pas trop car j'ai également des fonctions Notify_print (voir ci-dessous) qui elle ne pose aucun problème :
void Notify_print ( char* txt ) {
Serial.write(txt);
#if defined (ESP8266)
uint8_t i;
for(i = 0; i < MAX_SRV_CLIENTS; i++){
if (serverClients[i] && serverClients[i].connected()){
serverClients[i].print(txt);
delay(1);
}
}
#endif
}
Une idée du pourquoi et comment le résoudre ?
voici le log d'erreur :
test-pointeur.ino: In function 'void loop()':
test-pointeur:44: error: invalid conversion from 'char' to 'char*' [-fpermissive]
test-pointeur:29: error: initializing argument 1 of 'void Notify_write(char*)' [-fpermissive]
In file included from C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/ESP8266WiFi.h:32:0,
from test-pointeur.ino:2:
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h: In instantiation of 'size_t WiFiClient::write(T&) [with T = char*; size_t = unsigned int]':
test-pointeur.ino:35:35: required from here
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:78:28: error: request for member 'available' in 'src', which is of non-class type 'char*'
while (src.available() > WIFICLIENT_MAX_PACKET_SIZE){
^
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:79:7: error: request for member 'read' in 'src', which is of non-class type 'char*'
src.read(obuf, WIFICLIENT_MAX_PACKET_SIZE);
^
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:87:38: error: request for member 'available' in 'src', which is of non-class type 'char*'
uint16_t leftLen = src.available();
^
C:\Users\xxx\AppData\Roaming\Arduino15\packages\esp8266\hardware\esp8266\1.6.5-1160-gef26c5f\libraries\ESP8266WiFi\src/WiFiClient.h:88:5: error: request for member 'read' in 'src', which is of non-class type 'char*'
src.read(obuf, leftLen);
^
invalid conversion from 'char' to 'char*' [-fpermissive]
Merci XavierMiller de prendre le temps de me répondre.
Alors oui je vais remplacer tous les Serial. par des Notify_ et je vais créer des fonctions Notify_write(),Notify_print(), ect ...
J'ai réduit la code a sa plus simple expression pour isoler le problème que je rencontre.
Voila le code (entier) qui illustre mon problème :
void setup() {
Serial.begin(115200);
#if defined (ESP8266)
//ici sera ajouter le code pour initialiser le wifi
#endif
}
void Notify_write ( char* val ) {
Serial.write(val); #if defined (ESP8266)
//ici sera ajouter le code pour renvoyer aussi vers le wifi si le code est compilé pour ESP8266 #endif
}
void loop() {
// Serial.write(';'); est remplacé par Notify_write pour pouvoir avoir une sortie sur serial ET sur wifi
Notify_write(';');
}
Maintenant voici l'erreur que j'ai en compilant ce code (pour n'importe quelle board) :
Les options de compilation ont été modifiées, tout sera recompilé
test-pointeur.ino: In function 'void loop()':
test-pointeur:18: error: invalid conversion from 'char' to 'char*' [-fpermissive]
test-pointeur:9: error: initializing argument 1 of 'void Notify_write(char*)' [-fpermissive]
invalid conversion from 'char' to 'char*' [-fpermissive]
Ce rapport contiendrait plus d'informations si l'option
"Montrer les informations de sortie pendant la compilation"
était activée dans Fichier > Préférences.
Pourtant c'est bien un pointeur char qu'il faut, non ?
Peux-tu illustrer ta proposition sur cet exemple :
void setup() {
Serial.begin(115200);
#if defined (ESP8266)
//ici sera ajouter le code pour initialiser le wifi
#endif
}
void Notify_write ( char* val ) {
Serial.write(val);
#if defined (ESP8266)
//ici sera ajouter le code pour renvoyer aussi vers le wifi si le code est compilé pour ESP8266
#endif
}
void loop() {
// Serial.write(';'); est remplacé par Notify_write pour pouvoir avoir une sortie sur serial ET sur wifi
Notify_write(';');
}
grâce à toi j'ai découvert les templates puis en me documentant un peu les classes. Du coup j'ai décidé de faire une classe avec plusieurs méthodes et les templates pour les types des arguments.
Au final voilà ce que donne l'exemple :
class Notify
{
public:
template<typename Tb>
void begin( const Tb & baud )
{
Serial.begin(baud);
#if defined (ESP8266)
// plein de truc
#endif
}
template<typename Tw>
void write( const Tw & val )
{
Serial.write(val);
#if defined (ESP8266)
// plein de truc
#endif
}
template<typename Tp>
void print( const Tp & txt )
{
Serial.print(txt);
#if defined (ESP8266)
// plein de truc
#endif
}
void print( const __FlashStringHelper* text )
{
Serial.print(text);
#if defined (ESP8266)
// plein de truc
#endif
}
template<typename Tpln>
void println( const Tpln & txtln )
{
Serial.println(txtln);
#if defined (ESP8266)
// plein de truc
#endif
}
};
Notify nfy;
void setup() {
nfy.begin(115200);
}
void loop() {
nfy.write('!');
delay(1000);
nfy.print("*");
delay(1000);
nfy.print(F("......"));
delay(1000);
nfy.println("?");
delay(1000);
}
Encore merci, j'ai appris beaucoup de choses aujourd'hui
Je me permets de remonter ce Topic car il me semble que le template ne gère pas tout les cas.
voici un petit exemple :
// Notifying
class Notif
{
public:
template<typename Tp>
void print( const Tp & txt )
{
Serial.print(txt);
}
void print( const __FlashStringHelper* Ftxt )
{
Serial.print(Ftxt);
}
};
Notif Notify;
void PrintHex8(uint8_t *data, uint8_t length) { // prints 8-bit data in hex (lowercase)
char tmp[length*2+1];
byte first ;
int j=0;
for (uint8_t i=0; i<length; i++) {
first = (data[i] >> 4) | 48;
if (first > 57) tmp[j] = first + (byte)39;
else tmp[j] = first ;
j++;
first = (data[i] & 0x0F) | 48;
if (first > 57) tmp[j] = first + (byte)39;
else tmp[j] = first;
j++;
}
tmp[length*2] = 0;
Notify.print(tmp);
}
// call function
byte data[18]={1,1,1,0,1,0,0,1};
PrintHex8( data,2);
Et voilà ce que me dit le compilateur :
Arduino : 1.6.7 (Windows 7), Carte : "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"
...
C:\Users\xxx\Documents\Arduino\test\test.ino: In function 'void PrintHex8(uint8_t*, uint8_t)':
test:36: error: no matching function for call to 'Notif::print(char [(((sizetype)((ssizetype)(((int)length) * 2))) + 1)])'
Notify.print(tmp);
^
C:\Users\xxx\Documents\Arduino\test\test.ino:36:19: note: candidates are:
C:\Users\xxx\Documents\Arduino\test\test.ino:7:10: note: template<class Tp> void Notif::print(const Tp&)
void print( const Tp & txt )
^
C:\Users\xxx\Documents\Arduino\test\test.ino:7:10: note: template argument deduction/substitution failed:
C:\Users\xxx\Documents\Arduino\test\test.ino:36:19: note: variable-sized array type 'char [(((sizetype)((ssizetype)(((int)length) * 2))) + 1)]' is not a valid template argument
Notify.print(tmp);
^
C:\Users\xxx\Documents\Arduino\test\test.ino:11:10: note: void Notif::print(const __FlashStringHelper*)
void print( const __FlashStringHelper* Ftxt )
^
C:\Users\xxx\Documents\Arduino\test\test.ino:11:10: note: no known conversion for argument 1 from 'char [(((sizetype)((ssizetype)(((int)length) * 2))) + 1)]' to 'const __FlashStringHelper*'
C:\Users\xxx\Documents\Arduino\test\test.ino: At global scope:
test:42: error: expected constructor, destructor, or type conversion before '(' token
PrintHex8( data,2);
^
exit status 1
no matching function for call to 'Notif::print(char [(((sizetype)((ssizetype)(((int)length) * 2))) + 1)])'
Le but est de remplacer tout les Serial.print() d'un programme existant par des Notify.print(). Le notify permettant de faire des Serial.print() et d'autres choses.
J'ai donc sur les conseils de XavierMiller utiliser des templates pour gérer les différents types de variable dans une classe Notify (qui comprends entre autre une fonction print).
Mais a priori le template ne gère pas tout les cas possible, j'ai donc mis un exemple simplifié de ce qui pose problème.
Si tu vois comment gérer ce cas particulier, je veux bien quelques conseils