Envoyé par
naute
J'ai le plaisir de vous annoncer la mise en ligne du tutoriel :
Merci pour cela. Quelques commentaires constructifs (éventuellement
) sur des points de détails (ou pas)
Comme vous pouvez le constater, j’ai légèrement remanié ce code pour le rendre plus lisible, notamment en ajoutant les indentations. Je peux à présent le faire sans soucis, car ce code ne sera plus intégré au sketch Arduino, et donc, la place qu’il occupe ne sera plus un problème.
--> comme vous le dites plus loin, il faudra quand même un jour ou l'autre émettre ce texte vers un client. Moins on aura d'octets à envoyer, plus rapide sera la transmission. Alors bien qu'en théorie c'est sympa d'avoir un fichier HTML lisible et bien indenté, en pratique il vaudrait mieux le stocker le plus compact possible.
Dans le code d'exemple de réception
1 2 3 4 5 6 7 8 9 10 11
| while (client.available())
{
char carLu = client.read();
if (carLu != 10)
{
reception += carLu;
}
else
{
break;
} |
il vaut mieux éviter les chiffres magique et remplacer 10 directement par '\n' (et mettre un petit commentaire // a-t-on reçu la fin de ligne.)
Cette réception n'est pas correcte en général. Elle fonctionne car vous avez un peu de chance sur le timing.
Il se pourrait que "client.available()" soit vide mais qu'on n'ait pas encore reçu toute la requête si la connexion ethernet est très lente ou le client pas rapide et donc que vous n'ayez pas encore reçu tout le "GET / HTTP/1.1" dans votre chaîne.
Normalement il faut lire jusqu'à une ligne vide (fin de l'en-tête) ou un timeout éventuellement et pas dépendre de la rapidité de vidage du buffer client par rapport à la rapidité de remplissage.
La
documentation Arduino propose
1 2 3 4 5 6 7 8 9 10 11
| // an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
... |
Vous pourriez prendre la même approche pour lire jusqu'au '\n'.
Cela dit et en référence à votre premier tuto où vous dites
Pourquoi ce test, alors que la ligne reception += carlu; suffit pour récupérer la chaîne reçue ? En fait, comme nous le verrons ultérieurement, seule la première ligne envoyée par le navigateur du client nous intéresse. Chaque ligne se termine par le caractère de code ASCII 10, appelé caractère de fin de ligne (LF pour Line Feed en anglais). Ce test, qui nous permet de détecter la fin de la première ligne, va donc également nous permettre d’empêcher la récupération des caractères inutiles contenus dans le tampon. Cela permet, d’une part, de gagner du temps, et, d’autre part, de ne stocker dans la variable reception que les renseignements utiles et donc d’éviter d’encombrer pour rien la mémoire vive dont la capacité n’est pas phénoménale
--> A noter que la bibliothèque considère qu'un client est toujours connecté même si on a envoyé close tant qu'on n'a pas vidé son buffer (available() n'est pas nul). Le client n'est pas libéré, j'ai jamais regardé en détail mais il y a peut-être une fuite mémoire si on ne vide pas ce buffer.
Quand vous dites:
Malheureusement, la bibliothèque SdFat ne gère pas la réinscription automatique du lecteur sur le bus SPI lors de la réinsertion de la carte microSD
ce n'est pas la faute du développeur. ça vient du fait que les lecteurs n'ont pas pour la plupart le mécanisme de détection d'éjection. il l'a
mentionné ici
There is no reliable way to detect insertion of an SD without a detect switch. Many sockets have pull-ups or other problems so SdFat does not have a function to detect SD insertion
.
Quand vous faites votre fonction accusé de réception
1 2 3 4 5 6 7 8
| void arHtml(EthernetClient nomClient, char type)
{
nomClient.println(F("HTTP/1.1 200 OK"));
nomClient.print(F("Content-Type: "));
nomClient.println(type);
nomClient.println(F("Connection: close"));
nomClient.println();
} |
il faut passer le client
par référence -->
void arHtml(EthernetClient& nomClient, char type)
sinon vous dupliquez l'objet client et il n'est pas prévu pour cela (+impact mémoire).
de manière générale, la duplication mémoire dans un buffer n'est pas nécessaire quand vous faites
1 2 3 4 5
| void envoiFichier(EthernetClient nomClient, String fichierEnCours)
{
char tableau[fichierEnCours.length()+1];
fichierEnCours.toCharArray(tableau, fichierEnCours.length()+1);
if (SD.exists(tableau)) {.... |
Comme la méthode appelée ne modifie pas la cString passée en paramètre, il suffirait de demander la cString sous-jacente à votre String . De plus là encore on ne veut pas dupliquer la mémoire pour le nom du fichier il faut donc passer par référence.
On ferait donc
1 2 3
| void envoiFichier(EthernetClient& nomClient, String& fichierEnCours)
{
if (SD.exists(fichierEnCours.c_str())) {.... |
MAIS - comme vous appelez ces fonctions directement avec un cString, le plus simple reste de définir le paramètre de la bonne façon:
1 2 3
| void envoiFichier(EthernetClient& nomClient, const char* fichierEnCours)
{
if (SD.exists(fichierEnCours)) {.... |
Dans l'absolu on essayerait d'éviter toute la classe String, elle prend aussi plein de place en mémoire (elle vous fait perdre 1.5ko de mémoire flash), et travailler avec des tableaux de caractères. c'est une bonne habitude à prendre sur petits micros-contrôleurs.
En espérant que ce soit utile
bonne journée de confinement à toutes et tous!
2 |
0 |